pymud 0.21.3.post1__py3-none-any.whl → 0.21.4.post1__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/decorators.py CHANGED
@@ -1,4 +1,4 @@
1
- import sys, functools, traceback
1
+ import functools, traceback
2
2
  from typing import Union, Optional, List
3
3
 
4
4
  def print_exception(session, e: Exception):
pymud/dialogs.py CHANGED
@@ -1,9 +1,9 @@
1
1
  import asyncio, webbrowser
2
- from typing import Any, Callable, Iterable, List, Tuple, Union
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
5
- from prompt_toolkit.layout.dimension import Dimension, D
6
- from prompt_toolkit import ANSI, HTML
2
+ from typing import Any
3
+ from prompt_toolkit.layout import AnyContainer, VSplit, HSplit, Window, WindowAlign
4
+ from prompt_toolkit.widgets import Dialog, Label, TextArea, Frame, RadioList
5
+ from prompt_toolkit.layout.dimension import D
6
+ from prompt_toolkit import HTML
7
7
  from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
8
8
  from prompt_toolkit.formatted_text import FormattedText, AnyFormattedText
9
9
  from prompt_toolkit.application.current import get_app
pymud/extras.py CHANGED
@@ -1,39 +1,24 @@
1
1
  # External Libraries
2
- from functools import lru_cache
3
2
  from unicodedata import east_asian_width
4
3
  from wcwidth import wcwidth
5
4
  from dataclasses import dataclass
6
- import time, re, logging, linecache, os
5
+ import time, re, linecache, os
7
6
  from typing import Optional, List, Dict
8
- from typing import Iterable, NamedTuple, Optional, Union, Tuple
7
+ from typing import Iterable, Optional, Tuple
9
8
  from prompt_toolkit import ANSI
10
9
  from prompt_toolkit.application import get_app
11
- from prompt_toolkit.buffer import Buffer
12
- from prompt_toolkit.formatted_text import to_formatted_text, fragment_list_to_text
10
+ from prompt_toolkit.formatted_text import to_formatted_text
13
11
  from prompt_toolkit.formatted_text.base import OneStyleAndTextTuple
14
12
  from prompt_toolkit.layout.controls import UIContent, UIControl
15
- from prompt_toolkit.layout.processors import Processor, Transformation
16
13
  from prompt_toolkit.application.current import get_app
17
- from prompt_toolkit.buffer import Buffer
18
- from prompt_toolkit.document import Document
19
14
  from prompt_toolkit.data_structures import Point
20
15
  from prompt_toolkit.layout.controls import UIContent, FormattedTextControl
21
- from prompt_toolkit.lexers import Lexer
22
16
  from prompt_toolkit.mouse_events import MouseButton, MouseEvent, MouseEventType
23
- from prompt_toolkit.selection import SelectionType
24
- from prompt_toolkit.buffer import Buffer, ValidationState
25
- from prompt_toolkit.utils import Event
26
17
 
27
- from prompt_toolkit.filters import (
28
- FilterOrBool,
29
- )
30
18
  from prompt_toolkit.formatted_text import (
31
19
  StyleAndTextTuples,
32
20
  to_formatted_text,
33
21
  )
34
- from prompt_toolkit.formatted_text.utils import fragment_list_to_text
35
- from prompt_toolkit.history import InMemoryHistory
36
- from prompt_toolkit.key_binding.key_bindings import KeyBindingsBase
37
22
  from prompt_toolkit.layout.containers import (
38
23
  Window,
39
24
  WindowAlign,
@@ -42,12 +27,6 @@ from prompt_toolkit.layout.controls import (
42
27
 
43
28
  FormattedTextControl,
44
29
  )
45
- from prompt_toolkit.layout.processors import (
46
- Processor,
47
- TransformationInput,
48
- Transformation
49
- )
50
- from prompt_toolkit.lexers import Lexer
51
30
  from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
52
31
  from prompt_toolkit.utils import get_cwidth
53
32
  from prompt_toolkit.widgets import Button, MenuContainer, MenuItem
@@ -56,7 +35,6 @@ from prompt_toolkit.widgets.base import Border
56
35
  from prompt_toolkit.layout.screen import _CHAR_CACHE, Screen, WritePosition
57
36
  from prompt_toolkit.layout.utils import explode_text_fragments
58
37
  from prompt_toolkit.formatted_text.utils import (
59
- fragment_list_to_text,
60
38
  fragment_list_width,
61
39
  )
62
40
 
@@ -236,7 +214,6 @@ class VSplitWindow(Window):
236
214
  upper = (total - 1) // 2
237
215
  below = total - upper - 1
238
216
 
239
- #if isNotMargin:
240
217
  if isinstance(self.content, PyMudBufferControl):
241
218
  b = self.content.buffer
242
219
  if not b:
@@ -261,7 +238,6 @@ class VSplitWindow(Window):
261
238
 
262
239
  else:
263
240
  # 若内容行数大于屏幕行数,则倒序复制,确保即使有自动折行时,最后一行也保持在屏幕最底部
264
-
265
241
  y = total
266
242
  lineno = line_count
267
243
 
@@ -273,13 +249,10 @@ class VSplitWindow(Window):
273
249
  line = ui_content.get_line(lineno)
274
250
  visible_line_to_row_col[y] = (lineno, horizontal_scroll)
275
251
  copy_line(line, lineno, 0, y, is_input=True)
276
-
277
252
 
278
253
  else:
279
254
  # 有split window
280
255
 
281
-
282
-
283
256
  # 先复制下半部分,倒序复制,确保即使有自动折行时,最后一行也保持在屏幕最底部
284
257
  y = total
285
258
  lineno = line_count
@@ -298,7 +271,7 @@ class VSplitWindow(Window):
298
271
  # 复制上半部分,正序复制,确保即使有自动折行时,第一行也保持在屏幕最顶部
299
272
  y = -vertical_scroll_2
300
273
  lineno = start_lineno
301
- while y <= below and lineno < line_count:
274
+ while y < below and lineno < line_count:
302
275
  line = ui_content.get_line(lineno)
303
276
  visible_line_to_row_col[y] = (lineno, horizontal_scroll)
304
277
  x = 0
@@ -385,7 +358,7 @@ class VSplitWindow(Window):
385
358
  if not b:
386
359
  return
387
360
  start_lineno = b.start_lineno
388
- if (start_lineno >= 0) and (start_lineno < b.lineCount - len(info.displayed_lines)):
361
+ if (start_lineno >= 0) and (start_lineno < b.lineCount - (len(info.displayed_lines) - 1) // 2):
389
362
  b.start_lineno = b.start_lineno + 1
390
363
  else:
391
364
  b.start_lineno = -1
@@ -409,7 +382,8 @@ class VSplitWindow(Window):
409
382
  b.start_lineno = 0
410
383
 
411
384
  else:
412
- b.start_lineno = b.lineCount - len(info.displayed_lines) - 1
385
+ b.start_lineno = b.lineCount - (len(info.displayed_lines) - 1) // 2
386
+
413
387
 
414
388
 
415
389
  class EasternButton(Button):
@@ -532,14 +506,14 @@ class SessionSelectionState:
532
506
  if self.start_row >= 0 and self.end_row >= 0 and self.start_col >= 0 and self.end_col >= 0:
533
507
  if (self.start_row == self.end_row) and (self.start_col == self.end_col):
534
508
  return False
535
- elif self.start_row > self.end_row:
536
- srow, scol = self.end_row, self.end_col
537
- erow, ecol = self.start_row, self.start_col
538
- self.start_row, self.end_row = srow, erow
539
- self.start_col, self.end_col = scol, ecol
540
- elif self.start_row == self.end_row and self.start_col > self.end_col:
541
- scol, ecol = self.end_col, self.start_col
542
- self.start_col, self.end_col = scol, ecol
509
+ # elif self.start_row > self.end_row:
510
+ # srow, scol = self.end_row, self.end_col
511
+ # erow, ecol = self.start_row, self.start_col
512
+ # self.start_row, self.end_row = srow, erow
513
+ # self.start_col, self.end_col = scol, ecol
514
+ # elif self.start_row == self.end_row and self.start_col > self.end_col:
515
+ # scol, ecol = self.end_col, self.start_col
516
+ # self.start_col, self.end_col = scol, ecol
543
517
 
544
518
  return True
545
519
 
@@ -548,10 +522,50 @@ class SessionSelectionState:
548
522
  @property
549
523
  def rows(self):
550
524
  if self.is_valid():
551
- return self.end_row - self.start_row + 1
525
+ return abs(self.end_row - self.start_row) + 1
552
526
  else:
553
527
  return 0
554
528
 
529
+ @property
530
+ def actual_start_row(self):
531
+ if self.is_valid():
532
+ if self.start_row <= self.end_row:
533
+ return self.start_row
534
+ else:
535
+ return self.end_row
536
+
537
+ return -1
538
+
539
+ @property
540
+ def actual_start_col(self):
541
+ if self.is_valid():
542
+ if self.start_row <= self.end_row:
543
+ return self.start_col
544
+ else:
545
+ return self.end_col
546
+
547
+ return -1
548
+
549
+ @property
550
+ def actual_end_row(self):
551
+ if self.is_valid():
552
+ if self.start_row <= self.end_row:
553
+ return self.end_row
554
+ else:
555
+ return self.start_row
556
+
557
+ return -1
558
+
559
+ @property
560
+ def actual_end_col(self):
561
+ if self.is_valid():
562
+ if self.start_row <= self.end_row:
563
+ return self.end_col
564
+ else:
565
+ return self.start_col
566
+
567
+ return -1
568
+
555
569
 
556
570
  class BufferBase:
557
571
  def __init__(self, name, newline = "\n", max_buffered_lines = 10000) -> None:
@@ -561,6 +575,8 @@ class BufferBase:
561
575
  self.start_lineno = -1
562
576
  self.selection = SessionSelectionState(-1, -1, -1, -1)
563
577
 
578
+ self.mouse_point = Point(-1, -1)
579
+
564
580
  def clear(self):
565
581
  pass
566
582
 
@@ -576,12 +592,13 @@ class BufferBase:
576
592
  def selection_range_at_line(self, lineno: int) -> Optional[Tuple[int, int]]:
577
593
  if self.selection.is_valid():
578
594
  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)
595
+
596
+ if lineno == self.selection.actual_start_row:
597
+ return (self.selection.actual_start_col, len(self.getLine(lineno)))
598
+ elif lineno == self.selection.actual_end_row:
599
+ return (0, self.selection.actual_end_col)
600
+ elif lineno > self.selection.actual_start_row and lineno < self.selection.actual_end_row:
601
+ return (0, len(self.getLine(lineno)))
585
602
 
586
603
  elif self.selection.rows == 1:
587
604
  if lineno == self.selection.start_row:
@@ -639,13 +656,11 @@ class SessionBuffer(BufferBase):
639
656
  ## limit buffered lines
640
657
  if len(self._lines) > self.max_buffered_lines:
641
658
  diff = len(self._lines) - self.max_buffered_lines
642
- # 分屏状态下,暂时不动态调整数据
643
- if self.start_lineno < 0:
644
- del self._lines[:diff]
645
- ## adjust selection
646
- if self.selection.start_row >= 0:
647
- self.selection.start_row -= diff
648
- self.selection.end_row -= diff
659
+ del self._lines[:diff]
660
+ ## adjust selection
661
+ if self.selection.start_row >= 0:
662
+ self.selection.start_row -= diff
663
+ self.selection.end_row -= diff
649
664
 
650
665
  get_app().invalidate()
651
666
 
@@ -707,8 +722,9 @@ class PyMudBufferControl(UIControl):
707
722
  self.buffer = buffer
708
723
 
709
724
  # 为MUD显示进行校正的处理,包括对齐校正,换行颜色校正等
710
- self.FULL_BLOCKS = set("▂▃▅▆▇▄█")
711
- self.SINGLE_LINES = set("┌└├┬┼┴╭╰─")
725
+ self.FULL_BLOCKS = set("▂▃▅▆▇▄█━◇◆")
726
+ self.SINGLE_LINES = set("┠┌└├┬┼┴╭╰─")
727
+ self.SINGLE_LINES_LEFT = set("┨┘┐┤")
712
728
  self.DOUBLE_LINES = set("╔╚╠╦╪╩═")
713
729
  self.ALL_COLOR_REGX = re.compile(r"(?:\[[\d;]+m)+")
714
730
  self.AVAI_COLOR_REGX = re.compile(r"(?:\[[\d;]+m)+(?!$)")
@@ -734,17 +750,31 @@ class PyMudBufferControl(UIControl):
734
750
 
735
751
  def width_correction(self, line: str) -> str:
736
752
  new_str = []
737
- for ch in line:
738
- new_str.append(ch)
753
+ for idx, ch in enumerate(line):
754
+
739
755
  if (east_asian_width(ch) in "FWA") and (wcwidth(ch) == 1):
756
+
740
757
  if ch in self.FULL_BLOCKS:
741
758
  new_str.append(ch)
759
+ new_str.append(ch)
742
760
  elif ch in self.SINGLE_LINES:
761
+ new_str.append(ch)
743
762
  new_str.append("─")
744
763
  elif ch in self.DOUBLE_LINES:
764
+ new_str.append(ch)
745
765
  new_str.append("═")
766
+ elif ch in self.SINGLE_LINES_LEFT:
767
+ new_str.append("─")
768
+ new_str.append(ch)
769
+ elif idx == len(line) - 1:
770
+ new_str.append(" ")
771
+ new_str.append(ch)
746
772
  else:
773
+ new_str.append(ch)
747
774
  new_str.append(' ')
775
+ else:
776
+ new_str.append(ch)
777
+
748
778
 
749
779
  return "".join(new_str)
750
780
 
@@ -752,18 +782,29 @@ class PyMudBufferControl(UIControl):
752
782
  return line.replace("\r", "").replace("\x00", "")
753
783
 
754
784
  def tab_correction(self, line: str):
755
- return line.replace("\t", " " * Settings.client["tabstop"])
785
+ from .session import Session
786
+ while "\t" in line:
787
+ tab_index = line.find("\t")
788
+ left, right = line[:tab_index], line[tab_index + 1:]
789
+ left_width = get_cwidth(Session.PLAIN_TEXT_REGX.sub("", left))
790
+ tab_width = Settings.client["tabstop"] - (left_width % Settings.client["tabstop"])
791
+ line = left + " " * tab_width + right
792
+
793
+ return line
756
794
 
757
795
  def line_correction(self, line: str):
758
796
  # 处理\r符号(^M)
759
797
  line = self.return_correction(line)
760
- # 处理Tab(\r)符号(^I)
761
- line = self.tab_correction(line)
762
798
 
763
799
  # 美化(解决中文英文在Console中不对齐的问题)
764
800
  if Settings.client["beautify"]:
765
801
  line = self.width_correction(line)
766
802
 
803
+ # 处理Tab(\r)符号(^I)对齐
804
+ line = self.tab_correction(line)
805
+
806
+ line += "\u200B" # 最后添加一个不可见字符,用于允许选择行时选到最后一个字符
807
+
767
808
  return line
768
809
 
769
810
  def create_content(self, width: int, height: int) -> UIContent:
@@ -878,6 +919,7 @@ class PyMudBufferControl(UIControl):
878
919
 
879
920
  if buffer:
880
921
  # Set the selection position.
922
+ buffer.mouse_point = position
881
923
  if mouse_event.event_type == MouseEventType.MOUSE_DOWN:
882
924
  buffer.exit_selection()
883
925
  buffer.selection.start_row = position.y
@@ -888,9 +930,10 @@ class PyMudBufferControl(UIControl):
888
930
  and mouse_event.button == MouseButton.LEFT
889
931
  ):
890
932
  # Click and drag to highlight a selection
891
- if buffer.selection.start_row >= 0:
933
+ if buffer.selection.start_row >= 0 and not (position.y == 0 and position.x == 0):
892
934
  buffer.selection.end_row = position.y
893
935
  buffer.selection.end_col = position.x
936
+
894
937
 
895
938
  elif mouse_event.event_type == MouseEventType.MOUSE_UP:
896
939
  # When the cursor was moved to another place, select the text.
@@ -899,7 +942,7 @@ class PyMudBufferControl(UIControl):
899
942
  # the cursor can never be after the text, so the cursor
900
943
  # will be repositioned automatically.)
901
944
 
902
- if buffer.selection.start_row >= 0:
945
+ if buffer.selection.start_row >= 0 and position.y >= 0:
903
946
  buffer.selection.end_row = position.y
904
947
  buffer.selection.end_col = position.x
905
948
 
pymud/logger.py CHANGED
@@ -1,4 +1,4 @@
1
- import os, re, datetime, threading, pathlib
1
+ import datetime, threading
2
2
  from queue import SimpleQueue, Empty
3
3
  from pathlib import Path
4
4
  from .settings import Settings
pymud/modules.py CHANGED
@@ -1,9 +1,9 @@
1
1
 
2
- import importlib, importlib.util, traceback
2
+ import importlib, importlib.util
3
3
  from typing import Any
4
4
  from .settings import Settings
5
5
  from .extras import DotDict
6
- from .decorators import exception, async_exception, PymudDecorator, print_exception
6
+ from .decorators import PymudDecorator, print_exception
7
7
 
8
8
  class PymudMeta(type):
9
9
  def __new__(cls, name, bases, attrs):
pymud/objects.py CHANGED
@@ -2,14 +2,13 @@
2
2
  MUD会话(session)中, 支持的对象列表
3
3
  """
4
4
 
5
- import asyncio, logging, re, importlib
6
- from abc import ABC, ABCMeta, abstractmethod
7
- from typing import Optional, Union, List, Dict, Tuple
5
+ import asyncio, logging, re
6
+ from typing import Union, List, Tuple
8
7
  from collections.abc import Iterable
9
8
  from collections import namedtuple
10
9
  from typing import Any
11
10
  from .settings import Settings
12
- from .decorators import exception, async_exception, print_exception
11
+ from .decorators import print_exception
13
12
 
14
13
  class CodeLine:
15
14
  """
pymud/protocol.py CHANGED
@@ -1,4 +1,4 @@
1
- import logging, asyncio, datetime, traceback
1
+ import logging, datetime
2
2
  from asyncio import BaseTransport, Protocol
3
3
  from .settings import Settings
4
4
 
pymud/pymud.py CHANGED
@@ -1,15 +1,13 @@
1
- import asyncio, functools, re, os, webbrowser, threading
1
+ import asyncio, functools, os, webbrowser, threading
2
2
  from datetime import datetime
3
- from pathlib import Path
4
- from prompt_toolkit.shortcuts import set_title, radiolist_dialog
3
+ from prompt_toolkit.shortcuts import set_title
5
4
  from prompt_toolkit.output import ColorDepth
6
5
  from prompt_toolkit.clipboard.pyperclip import PyperclipClipboard
7
6
  from prompt_toolkit import HTML
8
7
  from prompt_toolkit.buffer import Buffer
9
8
  from prompt_toolkit.application import Application
10
- from prompt_toolkit.filters import Condition
11
- from prompt_toolkit.key_binding import KeyBindings
12
- from prompt_toolkit.layout import ConditionalContainer, Float, VSplit, HSplit, Window, WindowAlign, ScrollbarMargin, NumberedMargin, to_dimension
9
+ from prompt_toolkit.filters import Condition, is_true, to_filter
10
+ from prompt_toolkit.layout import ConditionalContainer, Float, VSplit, HSplit, Window, WindowAlign
13
11
  from prompt_toolkit.layout.layout import Layout
14
12
  from prompt_toolkit.layout.controls import FormattedTextControl
15
13
  from prompt_toolkit.layout.dimension import D
@@ -18,26 +16,14 @@ from prompt_toolkit.styles import Style
18
16
  from prompt_toolkit.widgets import Label, TextArea
19
17
  from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
20
18
  from prompt_toolkit.cursor_shapes import CursorShape
21
- from prompt_toolkit.key_binding import KeyPress, KeyPressEvent
19
+ from prompt_toolkit.key_binding import KeyBindings, KeyPress, KeyPressEvent
22
20
  from prompt_toolkit.keys import Keys
23
- from prompt_toolkit.filters import (
24
- Condition,
25
- is_true,
26
- to_filter,
27
- )
28
- from prompt_toolkit.formatted_text import (
29
- Template,
30
- )
31
- from prompt_toolkit.layout.processors import (
32
- DisplayMultipleCursors,
33
- HighlightSearchProcessor,
34
- HighlightSelectionProcessor,
35
- )
21
+ from prompt_toolkit.formatted_text import Template
36
22
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
37
- from wcwidth import wcwidth, wcswidth
23
+ from wcwidth import wcswidth
38
24
 
39
25
  from .objects import CodeBlock
40
- from .extras import BufferBase, LogFileBuffer, SessionBuffer, PyMudBufferControl, EasternMenuContainer, VSplitWindow, DotDict, MenuItem
26
+ from .extras import BufferBase, LogFileBuffer, PyMudBufferControl, EasternMenuContainer, VSplitWindow, DotDict, MenuItem
41
27
  from .modules import Plugin
42
28
  from .session import Session
43
29
  from .settings import Settings
@@ -516,16 +502,17 @@ class PyMudApp:
516
502
  b = self.consoleView.buffer
517
503
  if b and b.selection.is_valid():
518
504
  if not raw:
519
- if b.selection.start_row == b.selection.end_row:
520
- if b.selection.end_col - b.selection.start_col == len(b.getLine(b.selection.start_row)):
505
+ #if b.selection.start_row == b.selection.end_row:
506
+ if b.selection.rows == 1:
507
+ if b.selection.actual_end_col - b.selection.actual_start_col >= len(b.getLine(b.selection.start_row)):
521
508
  # 单行且选中了整行,此时不校正显示位置匹配
522
- line = b.getLine(b.selection.start_row)
509
+ line = b.getLine(b.selection.actual_start_row)
523
510
  else:
524
511
  # 单行且选中了部分内容,此时校正显示位置匹配
525
- line = self.consoleView.line_correction(b.getLine(b.selection.start_row))
512
+ line = self.consoleView.line_correction(b.getLine(b.selection.actual_start_row))
526
513
 
527
- start = max(0, b.selection.start_col)
528
- end = min(len(line), b.selection.end_col)
514
+ start = max(0, b.selection.actual_start_col)
515
+ end = min(len(line) + 1, b.selection.actual_end_col)
529
516
  line_plain = Session.PLAIN_TEXT_REGX.sub("", line).replace("\r", "").replace("\x00", "")
530
517
  selection = line_plain[start:end]
531
518
  self.app.clipboard.set_text(selection)
@@ -535,7 +522,7 @@ class PyMudApp:
535
522
  else:
536
523
  # 多行只认行
537
524
  lines = []
538
- for row in range(b.selection.start_row, b.selection.end_row + 1):
525
+ for row in range(b.selection.actual_start_row, b.selection.actual_end_row + 1):
539
526
  line = b.getLine(row)
540
527
  line_plain = Session.PLAIN_TEXT_REGX.sub("", line).replace("\r", "").replace("\x00", "")
541
528
  lines.append(line_plain)
@@ -545,9 +532,10 @@ class PyMudApp:
545
532
 
546
533
  else:
547
534
  # RAW模式,直接复制原始内容
548
- if b.selection.start_row == b.selection.end_row:
535
+ #if b.selection.start_row == b.selection.end_row:
536
+ if b.selection.rows == 1:
549
537
  # 单行情况
550
- line = b.getLine(b.selection.start_row)
538
+ line = b.getLine(b.selection.actual_start_row)
551
539
  self.app.clipboard.set_text(line)
552
540
  self.set_status(Settings.gettext("msg_copy", line))
553
541
  if self.current_session:
@@ -556,7 +544,7 @@ class PyMudApp:
556
544
  else:
557
545
  # 多行只认行
558
546
  lines = []
559
- for row in range(b.selection.start_row, b.selection.end_row + 1):
547
+ for row in range(b.selection.actual_start_row, b.selection.actual_end_row + 1):
560
548
  line = b.getLine(row)
561
549
  lines.append(line)
562
550
  copy_raw_text = "\n".join(lines)
@@ -924,7 +912,14 @@ class PyMudApp:
924
912
  if not self._mouse_support:
925
913
  mouse_support = Settings.gettext("status_mouseinh") + " "
926
914
 
915
+ mouse = "0, 0"
916
+
927
917
  if self.current_session:
918
+ buffer = self.current_session.buffer
919
+ if buffer:
920
+ position = buffer.mouse_point
921
+ mouse = f"{position.y}, {position.x}"
922
+
928
923
  if self.current_session._ignore:
929
924
  tri_status = Settings.gettext("status_ignore") + " "
930
925
 
pymud/session.py CHANGED
@@ -3,7 +3,7 @@ from pathlib import Path
3
3
  from collections.abc import Iterable
4
4
  from collections import OrderedDict
5
5
  from prompt_toolkit.utils import get_cwidth
6
- from wcwidth import wcswidth, wcwidth
6
+ from wcwidth import wcswidth
7
7
  from typing import Union, Optional, Any, List, Tuple, Dict, Type
8
8
  from .logger import Logger
9
9
  from .extras import DotDict, SessionBuffer
@@ -11,7 +11,7 @@ from .protocol import MudClientProtocol
11
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
- from .decorators import exception, async_exception
14
+ from .decorators import exception
15
15
 
16
16
  class Session:
17
17
  """
pymud/settings.py CHANGED
@@ -15,7 +15,7 @@ class Settings:
15
15
  "APP 简要描述"
16
16
  __version__ = importlib.metadata.version("pymud")
17
17
  "APP 当前版本"
18
- __release__ = "2025-05-27"
18
+ __release__ = "2025-06-08"
19
19
  "APP 当前版本发布日期"
20
20
  __author__ = "本牛(newstart)@北侠"
21
21
  "APP 作者"
@@ -58,7 +58,7 @@ class Settings:
58
58
  "naws_width" : 150, # 客户端NAWS宽度
59
59
  "naws_height" : 40, # 客户端NAWS高度
60
60
  "newline" : "\n", # 客户端换行符
61
- "tabstop" : 4, # 制表符改成空格
61
+ "tabstop" : 8, # 制表符改成空格
62
62
  "seperator" : ";", # 多个命令分隔符(默认;)
63
63
  "appcmdflag" : "#", # app命令标记(默认#)
64
64
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pymud
3
- Version: 0.21.3.post1
3
+ Version: 0.21.4.post1
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>
@@ -66,6 +66,14 @@ Dynamic: license-file
66
66
 
67
67
  ## 版本更新信息
68
68
 
69
+ ### 0.21.4 (2025-06-08)
70
+
71
+ + 问题修复: 修复了在多行选择碰到空行时,会导致从头开始全选的问题。
72
+ + 问题修复: 修复了从后往前选择时,若再往后选择,会导致起始位置错误的问题。
73
+ + 问题修复: 修复了纯文本行单行部分复制时,最后一个字符无法被选中和复制的问题。
74
+ + 问题修复: 修复了美化模式下,当服务器使用tab对齐在本地显示中无法对齐的问题。为配合对齐,默认tabstop已修改为8。
75
+ + 功能调整: 当上下分屏显示时,上半屏也能显示到最后一行,而不是仅显示到分屏处位置。
76
+
69
77
  ### 0.21.3 (2025-06-02)
70
78
 
71
79
  + 问题修复: 修复了当缓存行数超过规定值时,由于代码错误导致清屏的问题。
@@ -0,0 +1,23 @@
1
+ pymud/__init__.py,sha256=oeHz0NM7_DwChCY8f_vQ_fBq0e_HoTd0cahCFwaavWE,806
2
+ pymud/__main__.py,sha256=lIOBiJmi8X-EWXVIx_OoxSgUZ0FYKlZI8hXVnLUYTJQ,61
3
+ pymud/decorators.py,sha256=rNuDaKk65Cwc9K6t0-BpqNUORs8-8X5Xsv6YaLQ7hc4,9839
4
+ pymud/dialogs.py,sha256=1xo5NJjch-u7RSRcclhvUE4gi8POgiZWK84lNx_HJbs,6891
5
+ pymud/extras.py,sha256=07YDRewb0aNzi-hkahUEU6fAnzcVkymc9MhTnDg2e-Y,37945
6
+ pymud/i18n.py,sha256=qLgvrmYhVfkTHKpbBR-LfYMOrGgi0skHrelbsj7ItbE,3034
7
+ pymud/logger.py,sha256=F2LBUogdzv2WXHo10CNorDh2VleAX1Wbwmxc3zznHlM,5823
8
+ pymud/main.py,sha256=zaSjNhpbX3FMulKg-UNFrdiIJO8sOmmrUQrkPOalB-4,10224
9
+ pymud/modules.py,sha256=CsOqY1c59CrejltCS4wf7QqdCr5k_ghel8AUqlKVGIw,11873
10
+ pymud/objects.py,sha256=NlKAQnV6v9lSkz94zmgb513HPxskY8-tXnOdrYhuktc,38629
11
+ pymud/pkuxkx.py,sha256=qDVry-Vd6MNui0NKWZFT52IpmP1sKS5Dz74EDY4tVGQ,14740
12
+ pymud/protocol.py,sha256=noptJs6K0L9qM8VZIeP65H4k9FPLGJqxvm3qY2iAwvI,48315
13
+ pymud/pymud.py,sha256=SrPGSls1QqrfSzctNpHV1gt_-M9WpOWi5cGH2VF8W6w,53483
14
+ pymud/session.py,sha256=sTswAPEl5GWcxzYmgovG8lOlflNTd5k8ggW6zJ6vcMY,154690
15
+ pymud/settings.py,sha256=V4wHKP2UjmX_l2bKJoUJSfNbH7vs3GZlN4u-1tRFbxA,7697
16
+ pymud/lang/i18n_chs.py,sha256=2cyaHHLwpYEBBwuQXyRTxa1opX53fTv1f8_QDQeGlC0,16836
17
+ pymud/lang/i18n_eng.py,sha256=jcPz6Y5UuxJBQLY_e8UnEF3GYTlnAD44C14Oj7sK-QI,45935
18
+ pymud-0.21.4.post1.dist-info/licenses/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
19
+ pymud-0.21.4.post1.dist-info/METADATA,sha256=16hQ1rEid5uC7uM7zLxpe86N-HRjtbea1zSbTkRDNT4,46537
20
+ pymud-0.21.4.post1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ pymud-0.21.4.post1.dist-info/entry_points.txt,sha256=diPUOtTkhgC1hVny7Cdg4aRhaHSynMQoraE7ZhJxUcw,37
22
+ pymud-0.21.4.post1.dist-info/top_level.txt,sha256=8Gp1eXjxixXjqhhti6tLCspV_8s9sNV3z5Em2_KRhD4,6
23
+ pymud-0.21.4.post1.dist-info/RECORD,,
@@ -1,23 +0,0 @@
1
- pymud/__init__.py,sha256=oeHz0NM7_DwChCY8f_vQ_fBq0e_HoTd0cahCFwaavWE,806
2
- pymud/__main__.py,sha256=lIOBiJmi8X-EWXVIx_OoxSgUZ0FYKlZI8hXVnLUYTJQ,61
3
- pymud/decorators.py,sha256=XaxcZqHw4s44lC2EAgB5kZmbNvJnHGmpZnoW75tUeNY,9844
4
- pymud/dialogs.py,sha256=4kHycr47UgKQUHGX-KMZvERuWViPjT4hNrGhbe4j-NU,7056
5
- pymud/extras.py,sha256=9jHJALSaydS-EMqDN4pHlkCcxii1uTz0Z3N1yuvcGlM,36778
6
- pymud/i18n.py,sha256=qLgvrmYhVfkTHKpbBR-LfYMOrGgi0skHrelbsj7ItbE,3034
7
- pymud/logger.py,sha256=WCsfXVkgl63qdq1RQEDJBnM7U0S6u8TeORFSMhcoydI,5840
8
- pymud/main.py,sha256=zaSjNhpbX3FMulKg-UNFrdiIJO8sOmmrUQrkPOalB-4,10224
9
- pymud/modules.py,sha256=DoCregng5iAj_Hq_yUvRPreRTv2Ehb6sV6_4jfdbsik,11912
10
- pymud/objects.py,sha256=Z77KHbg06jIx9cIEiyHkWI5i3but4PFeZS_m2WHsFrs,38729
11
- pymud/pkuxkx.py,sha256=qDVry-Vd6MNui0NKWZFT52IpmP1sKS5Dz74EDY4tVGQ,14740
12
- pymud/protocol.py,sha256=KNKJYj9HFRoUy-jigNfhiQdDOM_kRSJE17QFpBarQTg,48335
13
- pymud/pymud.py,sha256=40hn5XyMH9mtjimx_zG7N2M6fAGciee1izO08jsfFzQ,53486
14
- pymud/session.py,sha256=vzOIyc1F8PVP1XadcGt-n7XOoiawJzYsIEBe0FU5oKY,154716
15
- pymud/settings.py,sha256=S2sBEM7YtaDOVu3UpGfHBaU7zSB3Zhs7w-Z7PtdS0WQ,7697
16
- pymud/lang/i18n_chs.py,sha256=2cyaHHLwpYEBBwuQXyRTxa1opX53fTv1f8_QDQeGlC0,16836
17
- pymud/lang/i18n_eng.py,sha256=jcPz6Y5UuxJBQLY_e8UnEF3GYTlnAD44C14Oj7sK-QI,45935
18
- pymud-0.21.3.post1.dist-info/licenses/LICENSE.txt,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
19
- pymud-0.21.3.post1.dist-info/METADATA,sha256=cfW1c3rEM8IdImBWtB6um8f_t4qUKcEPZJtYNl-woqY,45905
20
- pymud-0.21.3.post1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
- pymud-0.21.3.post1.dist-info/entry_points.txt,sha256=diPUOtTkhgC1hVny7Cdg4aRhaHSynMQoraE7ZhJxUcw,37
22
- pymud-0.21.3.post1.dist-info/top_level.txt,sha256=8Gp1eXjxixXjqhhti6tLCspV_8s9sNV3z5Em2_KRhD4,6
23
- pymud-0.21.3.post1.dist-info/RECORD,,