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/pymud.py CHANGED
@@ -15,7 +15,7 @@ from prompt_toolkit.layout.controls import FormattedTextControl
15
15
  from prompt_toolkit.layout.dimension import D
16
16
  from prompt_toolkit.layout.menus import CompletionsMenu
17
17
  from prompt_toolkit.styles import Style
18
- from prompt_toolkit.widgets import Label, MenuItem, TextArea
18
+ from prompt_toolkit.widgets import Label, TextArea
19
19
  from prompt_toolkit.mouse_events import MouseEvent, MouseEventType
20
20
  from prompt_toolkit.cursor_shapes import CursorShape
21
21
  from prompt_toolkit.key_binding import KeyPress, KeyPressEvent
@@ -34,9 +34,10 @@ from prompt_toolkit.layout.processors import (
34
34
  HighlightSelectionProcessor,
35
35
  )
36
36
  from prompt_toolkit.auto_suggest import AutoSuggestFromHistory
37
+ from wcwidth import wcwidth, wcswidth
37
38
 
38
39
  from .objects import CodeBlock
39
- from .extras import MudFormatProcessor, SessionBuffer, EasternMenuContainer, VSplitWindow, SessionBufferControl, DotDict
40
+ from .extras import MudFormatProcessor, SessionBuffer, EasternMenuContainer, VSplitWindow, SessionBufferControl, DotDict, MenuItem
40
41
  from .modules import Plugin
41
42
  from .session import Session
42
43
  from .settings import Settings
@@ -75,7 +76,18 @@ class PyMudApp:
75
76
  构造PyMudApp对象实例,并加载替代配置。
76
77
  """
77
78
 
79
+ from .i18n import i18n_LoadLanguage, i18n_ListAvailableLanguages
80
+ # 加载默认chs语言内容,以防翻译不完整时,默认使用中文替代
81
+ i18n_LoadLanguage("chs")
82
+
78
83
  if cfg_data and isinstance(cfg_data, dict):
84
+ # load language from
85
+ language = Settings.language
86
+ if "language" in cfg_data.keys():
87
+ if cfg_data["language"] in i18n_ListAvailableLanguages() and cfg_data["language"] != "chs":
88
+ language = cfg_data["language"]
89
+ i18n_LoadLanguage(language)
90
+
79
91
  for key in cfg_data.keys():
80
92
  if key == "sessions":
81
93
  Settings.sessions = cfg_data[key]
@@ -89,6 +101,8 @@ class PyMudApp:
89
101
  Settings.styles.update(cfg_data[key])
90
102
  elif key == "keys":
91
103
  Settings.keys.update(cfg_data[key])
104
+ elif key == "language":
105
+ Settings.language = cfg_data[key]
92
106
 
93
107
  self._mouse_support = True
94
108
  self._plugins = DotDict() # 增加 插件 字典
@@ -303,26 +317,26 @@ class PyMudApp:
303
317
  body = self.body,
304
318
  menu_items=[
305
319
  MenuItem(
306
- Settings.text["world"],
320
+ Settings.gettext("world"),
307
321
  children=self.create_world_menus(),
308
322
  ),
309
323
  MenuItem(
310
- Settings.text["session"],
324
+ Settings.gettext("session"),
311
325
  children=[
312
- MenuItem(Settings.text["connect"], handler = self.act_connect),
313
- MenuItem(Settings.text["disconnect"], handler = self.act_discon),
314
- MenuItem(Settings.text["closesession"], handler = self.act_close_session),
315
- MenuItem(Settings.text["autoreconnect"], handler = self.act_autoreconnect),
326
+ MenuItem(Settings.gettext("disconnect"), handler = self.act_discon),
327
+ MenuItem(Settings.gettext("connect"), handler = self.act_connect),
328
+ MenuItem(Settings.gettext("closesession"), handler = self.act_close_session),
329
+ MenuItem(Settings.gettext("autoreconnect"), handler = self.act_autoreconnect),
316
330
  MenuItem("-", disabled=True),
317
- MenuItem(Settings.text["nosplit"], handler = self.act_nosplit),
318
- MenuItem(Settings.text["echoinput"], handler = self.act_echoinput),
319
- MenuItem(Settings.text["beautify"], handler = self.act_beautify),
320
- MenuItem(Settings.text["copy"], handler = self.act_copy),
321
- MenuItem(Settings.text["copyraw"], handler = self.act_copyraw),
322
- MenuItem(Settings.text["clearsession"], handler = self.act_clearsession),
331
+ MenuItem(Settings.gettext("nosplit"), handler = self.act_nosplit),
332
+ MenuItem(Settings.gettext("echoinput"), handler = self.act_echoinput),
333
+ MenuItem(Settings.gettext("beautify"), handler = self.act_beautify),
334
+ MenuItem(Settings.gettext("copy"), handler = self.act_copy),
335
+ MenuItem(Settings.gettext("copyraw"), handler = self.act_copyraw),
336
+ MenuItem(Settings.gettext("clearsession"), handler = self.act_clearsession),
323
337
  MenuItem("-", disabled=True),
324
338
 
325
- MenuItem(Settings.text["reloadconfig"], handler = self.act_reload),
339
+ MenuItem(Settings.gettext("reloadconfig"), handler = self.act_reload),
326
340
  ]
327
341
  ),
328
342
 
@@ -336,9 +350,9 @@ class PyMudApp:
336
350
  # ),
337
351
 
338
352
  MenuItem(
339
- Settings.text["help"],
353
+ Settings.gettext("help"),
340
354
  children=[
341
- MenuItem(Settings.text["about"], handler = self.act_about)
355
+ MenuItem(Settings.gettext("about"), handler = self.act_about)
342
356
  ]
343
357
  ),
344
358
 
@@ -359,7 +373,7 @@ class PyMudApp:
359
373
  def create_world_menus(self):
360
374
  "创建世界子菜单,其中根据本地pymud.cfg中的有关配置创建会话有关子菜单"
361
375
  menus = []
362
- menus.append(MenuItem(Settings.text["new_session"], handler = self.act_new))
376
+ menus.append(MenuItem(f'{Settings.gettext("new_session")}...', handler = self.act_new))
363
377
  menus.append(MenuItem("-", disabled=True))
364
378
 
365
379
  ss = Settings.sessions
@@ -367,14 +381,14 @@ class PyMudApp:
367
381
  for key, site in ss.items():
368
382
  menu = MenuItem(key)
369
383
  for name in site["chars"].keys():
370
- sub = MenuItem(name, handler = functools.partial(self._quickHandleSession, key, name))
384
+ sub = MenuItem(name, handler = functools.partial(self._quickHandleSession, key, name)) # type: ignore
371
385
  menu.children.append(sub)
372
386
  menus.append(menu)
373
387
 
374
388
  menus.append(MenuItem("-", disabled=True))
375
- menus.append(MenuItem(Settings.text["show_log"], handler = self.show_logSelectDialog))
389
+ menus.append(MenuItem(Settings.gettext("show_log"), handler = self.show_logSelectDialog))
376
390
  menus.append(MenuItem("-", disabled=True))
377
- menus.append(MenuItem(Settings.text["exit"], handler=self.act_exit))
391
+ menus.append(MenuItem(Settings.gettext("exit"), handler=self.act_exit))
378
392
 
379
393
  return menus
380
394
 
@@ -389,6 +403,8 @@ class PyMudApp:
389
403
  b = s.buffer
390
404
  elif self.showLog:
391
405
  b = self.logSessionBuffer
406
+ else:
407
+ b = None
392
408
 
393
409
  if isinstance(b, Buffer):
394
410
  if lines < 0:
@@ -437,7 +453,7 @@ class PyMudApp:
437
453
  def complete_autosuggest(self, event: KeyPressEvent):
438
454
  """快捷键右箭头→: 自动完成建议"""
439
455
  b = event.current_buffer
440
- if b.cursor_position == len(b.text):
456
+ if (b.cursor_position == len(b.text)) and b.auto_suggest:
441
457
  s = b.auto_suggest.get_suggestion(b, b.document)
442
458
  if s:
443
459
  b.insert_text(s.text, fire_event=False)
@@ -507,12 +523,10 @@ class PyMudApp:
507
523
  line = self.mudFormatProc.line_correction(b.document.current_line)
508
524
  start = max(0, scol)
509
525
  end = min(ecol, len(line))
510
- #line_plain = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", line, flags = re.IGNORECASE).replace("\r", "").replace("\x00", "")
511
526
  line_plain = Session.PLAIN_TEXT_REGX.sub("", line).replace("\r", "").replace("\x00", "")
512
- #line_plain = re.sub("\x1b\\[[^mz]+[mz]", "", line).replace("\r", "").replace("\x00", "")
513
527
  selection = line_plain[start:end]
514
528
  self.app.clipboard.set_text(selection)
515
- self.set_status("已复制:{}".format(selection))
529
+ self.set_status(Settings.gettext("msg_copy", selection))
516
530
  if self.current_session:
517
531
  self.current_session.setVariable("%copy", selection)
518
532
  else:
@@ -520,12 +534,11 @@ class PyMudApp:
520
534
  lines = []
521
535
  for row in range(srow, erow + 1):
522
536
  line = b.document.lines[row]
523
- #line_plain = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", line, flags = re.IGNORECASE).replace("\r", "").replace("\x00", "")
524
537
  line_plain = Session.PLAIN_TEXT_REGX.sub("", line).replace("\r", "").replace("\x00", "")
525
538
  lines.append(line_plain)
526
539
 
527
540
  self.app.clipboard.set_text("\n".join(lines))
528
- self.set_status("已复制:行数{}".format(1 + erow - srow))
541
+ self.set_status(Settings.gettext("msg_copylines", 1 + erow - srow))
529
542
 
530
543
  if self.current_session:
531
544
  self.current_session.setVariable("%copy", "\n".join(lines))
@@ -535,7 +548,7 @@ class PyMudApp:
535
548
  if srow == erow:
536
549
  line = b.document.current_line
537
550
  self.app.clipboard.set_text(line)
538
- self.set_status("已复制:{}".format(line))
551
+ self.set_status(Settings.gettext("msg_copy", line))
539
552
 
540
553
  if self.current_session:
541
554
  self.current_session.setVariable("%copy", line)
@@ -544,18 +557,13 @@ class PyMudApp:
544
557
  lines = b.document.lines[srow:erow+1]
545
558
  copy_raw_text = "".join(lines)
546
559
  self.app.clipboard.set_text(copy_raw_text)
547
- self.set_status("已复制:行数{}".format(1 + erow - srow))
560
+ self.set_status(Settings.gettext("msg_copylines", 1 + erow - srow))
548
561
 
549
562
  if self.current_session:
550
563
  self.current_session.setVariable("%copy", copy_raw_text)
551
564
 
552
- # data = self.consoleView.buffer.copy_selection()
553
- # self.app.clipboard.set_data(data)
554
- # self.set_status("已复制:{}".format(data.text))
555
-
556
- # self.current_session.setVariable("%copy", data.text)
557
565
  else:
558
- self.set_status("未选中任何内容...")
566
+ self.set_status(Settings.gettext("msg_no_selection"))
559
567
 
560
568
  def create_session(self, name, host, port, encoding = None, after_connect = None, scripts = None, userid = None):
561
569
  """
@@ -584,13 +592,19 @@ class PyMudApp:
584
592
 
585
593
  result = True
586
594
  else:
587
- self.set_status(f"错误!已存在一个名为{name}的会话,请更换名称再试.")
595
+ self.set_status(Settings.gettext("msg_session_exists", name))
588
596
 
589
597
  return result
590
598
 
591
599
  def show_logSelectDialog(self):
600
+ def correction_align_width(text, width):
601
+ "修正文本对齐宽度,防止ljust和rjust方法产生的中文宽度不对齐问题"
602
+ return width - wcswidth(text) + len(text)
592
603
  async def coroutine():
593
- head_line = " {}{}{}".format('记录文件名'.ljust(15), '文件大小'.rjust(16), '最后修改时间'.center(17))
604
+ title_filename = Settings.gettext("logfile_name").ljust(correction_align_width(Settings.gettext("logfile_name"), 20))
605
+ title_filesize = Settings.gettext("logfile_size").rjust(correction_align_width(Settings.gettext("logfile_size"), 20))
606
+ title_modified = Settings.gettext("logfile_modified").center(correction_align_width(Settings.gettext("logfile_modified"), 23))
607
+ head_line = " {}{}{}".format(title_filename, title_filesize, title_modified)
594
608
 
595
609
  log_list = list()
596
610
  files = [f for f in os.listdir('.') if os.path.isfile(f) and f.endswith('.log')]
@@ -663,7 +677,7 @@ class PyMudApp:
663
677
  async def coroutine():
664
678
  if self.current_session:
665
679
  if self.current_session.connected:
666
- dlgQuery = QueryDialog(HTML('<b fg="red">警告</b>'), HTML('<style fg="red">当前会话 {0} 还处于连接状态,确认要关闭?</style>'.format(self.current_session.name)))
680
+ dlgQuery = QueryDialog(HTML(f'<b fg="red">{Settings.gettext("warning")}</b>'), HTML(f'<style fg="red">{Settings.gettext("session_close_prompt", self.current_session.name)}</style>'))
667
681
  result = await self.show_dialog_as_float(dlgQuery)
668
682
  if result:
669
683
  self.current_session.disconnect()
@@ -696,7 +710,7 @@ class PyMudApp:
696
710
  self.activate_session(new_sess)
697
711
  #self.set_status(f"当前会话已切换为 {self.current_session.name}")
698
712
 
699
- asyncio.ensure_future(coroutine())
713
+ asyncio.ensure_future(coroutine()) # type: ignore
700
714
 
701
715
  # 菜单选项操作 - 开始
702
716
 
@@ -751,21 +765,21 @@ class PyMudApp:
751
765
  val = not Settings.client["beautify"]
752
766
  Settings.client["beautify"] = val
753
767
  if self.current_session:
754
- self.current_session.info(f"显示美化已{'打开' if val else '关闭'}!")
768
+ self.current_session.info(f'{Settings.gettext("msg_beautify")}{Settings.gettext("msg_open") if val else Settings.gettext("msg_close")}!')
755
769
 
756
770
  def act_echoinput(self):
757
771
  "菜单: 显示/隐藏输入指令"
758
772
  val = not Settings.client["echo_input"]
759
773
  Settings.client["echo_input"] = val
760
774
  if self.current_session:
761
- self.current_session.info(f"回显输入命令被设置为:{'打开' if val else '关闭'}")
775
+ self.current_session.info(f'{Settings.gettext("msg_echoinput")}{Settings.gettext("msg_open") if val else Settings.gettext("msg_close")}!')
762
776
 
763
777
  def act_autoreconnect(self):
764
778
  "菜单: 打开/关闭自动重连"
765
779
  val = not Settings.client["auto_reconnect"]
766
780
  Settings.client["auto_reconnect"] = val
767
781
  if self.current_session:
768
- self.current_session.info(f"自动重连被设置为:{'打开' if val else '关闭'}")
782
+ self.current_session.info(f'{Settings.gettext("msg_autoreconnect")}{Settings.gettext("msg_open") if val else Settings.gettext("msg_close")}')
769
783
 
770
784
  def act_copy(self):
771
785
  "菜单: 复制纯文本"
@@ -786,17 +800,7 @@ class PyMudApp:
786
800
 
787
801
  # 暂未实现该功能
788
802
  def act_change_layout(self, layout):
789
- #if isinstance(layout, STATUS_DISPLAY):
790
803
  self.status_display = layout
791
- #self.console_frame.body.reset()
792
- # if layout == STATUS_DISPLAY.HORIZON:
793
- # self.console_frame.body = self.console_with_horizon_status
794
- # elif layout == STATUS_DISPLAY.VERTICAL:
795
- # self.console_frame.body = self.console_with_vertical_status
796
- # elif layout == STATUS_DISPLAY.NONE:
797
- # self.console_frame.body = self.console_without_status
798
-
799
- #self.show_message("布局调整", f"已将布局设置为{layout}")
800
804
  self.app.invalidate()
801
805
 
802
806
  def act_exit(self):
@@ -808,7 +812,7 @@ class PyMudApp:
808
812
  con_sessions.append(session.name)
809
813
 
810
814
  if len(con_sessions) > 0:
811
- dlgQuery = QueryDialog(HTML('<b fg="red">程序退出警告</b>'), HTML('<style fg="red">尚有 {0} 个会话 {1} 还处于连接状态,确认要关闭?</style>'.format(len(con_sessions), ", ".join(con_sessions))))
815
+ dlgQuery = QueryDialog(HTML(f'<b fg="red">{Settings.gettext("warning_exit")}</b>'), HTML(f'<style fg="red">{Settings.gettext("app_exit_prompt", len(con_sessions), ", ".join(con_sessions))}</style>'))
812
816
  result = await self.show_dialog_as_float(dlgQuery)
813
817
  if result:
814
818
  for ss_name in con_sessions:
@@ -844,7 +848,7 @@ class PyMudApp:
844
848
 
845
849
  def get_input_prompt(self):
846
850
  "命令输入行提示符"
847
- return HTML(Settings.text["input_prompt"])
851
+ return HTML(Settings.gettext("input_prompt"))
848
852
 
849
853
  def btn_title_clicked(self, name, mouse_event: MouseEvent):
850
854
  "顶部会话标签点击切换鼠标事件"
@@ -906,17 +910,17 @@ class PyMudApp:
906
910
  "状态栏右侧内容"
907
911
  con_str, mouse_support, tri_status, beautify = "", "", "", ""
908
912
  if not Settings.client["beautify"]:
909
- beautify = "美化已关闭 "
913
+ beautify = Settings.gettext("status_nobeautify") + " "
910
914
 
911
915
  if not self._mouse_support:
912
- mouse_support = "鼠标已禁用 "
916
+ mouse_support = Settings.gettext("status_mouseinh") + " "
913
917
 
914
918
  if self.current_session:
915
919
  if self.current_session._ignore:
916
- tri_status = "全局禁用 "
920
+ tri_status = Settings.gettext("status_ignore") + " "
917
921
 
918
922
  if not self.current_session.connected:
919
- con_str = "未连接"
923
+ con_str = Settings.gettext("status_notconnect")
920
924
  else:
921
925
  dura = self.current_session.duration
922
926
  DAY, HOUR, MINUTE = 86400, 3600, 60
@@ -927,15 +931,14 @@ class PyMudApp:
927
931
  dura = dura - hours * HOUR
928
932
  mins = dura // MINUTE
929
933
  sec = dura - mins * MINUTE
930
-
931
934
  if days > 0:
932
- con_str = "已连接:{:.0f}{:.0f}小时{:.0f}{:.0f}".format(days, hours, mins, sec)
935
+ con_str = Settings.gettext("status_connected") + ": {0:.0f}{4}{1:.0f}{5}{2:.0f}{6}{3:.0f}{7}".format(days, hours, mins, sec, Settings.gettext("Day"), Settings.gettext("Hour"), Settings.gettext("Minute"), Settings.gettext("Second"))
933
936
  elif hours > 0:
934
- con_str = "已连接:{:.0f}小时{:.0f}{:.0f}".format(hours, mins, sec)
937
+ con_str = Settings.gettext("status_connected") + ": {0:.0f}{3}{1:.0f}{4}{2:.0f}{5}".format(hours, mins, sec, Settings.gettext("Hour"), Settings.gettext("Minute"), Settings.gettext("Second"))
935
938
  elif mins > 0:
936
- con_str = "已连接:{:.0f}{:.0f}".format(mins, sec)
939
+ con_str = Settings.gettext("status_connected") + ": {0:.0f}{2}{1:.0f}{3}".format(mins, sec, Settings.gettext("Minute"), Settings.gettext("Second"))
937
940
  else:
938
- con_str = "已连接:{:.0f}".format(sec)
941
+ con_str = Settings.gettext("status_connected") + ": {:.0f}{}".format(sec, Settings.gettext("Second"))
939
942
 
940
943
  return "{}{}{}{} {} {} ".format(beautify, mouse_support, tri_status, con_str, Settings.__appname__, Settings.__version__)
941
944
 
@@ -1056,7 +1059,7 @@ class PyMudApp:
1056
1059
  nothandle = not self._quickHandleSession(group, name)
1057
1060
 
1058
1061
  else:
1059
- errmsg = f'通过单一参数快速创建会话时,要使用 group.name 形式,如 #session pkuxkx.newstart'
1062
+ errmsg = Settings.gettext("msg_cmd_session_error")
1060
1063
 
1061
1064
  elif len(args) >= 3:
1062
1065
  session_name = args[0]
@@ -1096,7 +1099,7 @@ class PyMudApp:
1096
1099
  self.current_session.writeline("")
1097
1100
  else:
1098
1101
  try:
1099
- self.current_session.log.log(f"命令行键入: {cmd_line}\n")
1102
+ self.current_session.log.log(f"{Settings.gettext('msg_cmdline_input')} {cmd_line}\n")
1100
1103
 
1101
1104
  cb = CodeBlock(cmd_line)
1102
1105
  cb.execute(self.current_session)
@@ -1109,7 +1112,7 @@ class PyMudApp:
1109
1112
  elif (cmd_line == "#close") and self.showLog:
1110
1113
  self.act_close_session()
1111
1114
  else:
1112
- self.set_status("当前没有正在运行的session.")
1115
+ self.set_status(Settings.gettext("msg_no_session"))
1113
1116
 
1114
1117
  # 配置:命令行内容保留
1115
1118
  if Settings.client["remain_last_input"]:
@@ -1183,16 +1186,18 @@ class PyMudApp:
1183
1186
  async def show_dialog_as_float(self, dialog):
1184
1187
  "显示弹出式窗口."
1185
1188
  float_ = Float(content=dialog)
1186
- self.root_container.floats.insert(0, float_)
1189
+ if self.root_container.floats:
1187
1190
 
1188
- self.app.layout.focus(dialog)
1189
- result = await dialog.future
1190
- self.app.layout.focus(self.commandLine)
1191
+ self.root_container.floats.insert(0, float_)
1191
1192
 
1192
- if float_ in self.root_container.floats:
1193
- self.root_container.floats.remove(float_)
1193
+ self.app.layout.focus(dialog)
1194
+ result = await dialog.future
1195
+ self.app.layout.focus(self.commandLine)
1194
1196
 
1195
- return result
1197
+ if float_ in self.root_container.floats:
1198
+ self.root_container.floats.remove(float_)
1199
+
1200
+ return result
1196
1201
 
1197
1202
  async def run_async(self):
1198
1203
  "以异步方式运行本程序"
@@ -1247,7 +1252,7 @@ class PyMudApp:
1247
1252
  self._plugins[plugin.name] = plugin
1248
1253
  # plugin.onAppInit(self)
1249
1254
  except Exception as e:
1250
- self.set_status(f"文件: {plugins_dir}\\{file} 不是一个合法的插件文件,加载错误,信息为: {e}")
1255
+ self.set_status(Settings.gettext("msg_plugin_load_error", file, e))
1251
1256
 
1252
1257
  # 然后加载当前目录下的插件
1253
1258
  current_dir = os.path.abspath(".")
@@ -1262,7 +1267,7 @@ class PyMudApp:
1262
1267
  self._plugins[plugin.name] = plugin
1263
1268
  plugin.onAppInit(self)
1264
1269
  except Exception as e:
1265
- self.set_status(f"文件: {plugins_dir}\\{file} 不是一个合法的插件文件. 加载错误,信息为: {e}")
1270
+ self.set_status(Settings.gettext("msg_plugin_load_error", file, e))
1266
1271
 
1267
1272
  def reload_plugin(self, plugin: Plugin):
1268
1273
  "重新加载指定插件"