je-editor 0.0.202__py3-none-any.whl → 0.0.228__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.
Files changed (96) hide show
  1. je_editor/__init__.py +2 -2
  2. je_editor/code_scan/__init__.py +0 -0
  3. je_editor/code_scan/ruff_thread.py +58 -0
  4. je_editor/code_scan/watchdog_implement.py +56 -0
  5. je_editor/code_scan/watchdog_thread.py +78 -0
  6. je_editor/git_client/__init__.py +0 -0
  7. je_editor/git_client/commit_graph.py +77 -0
  8. je_editor/git_client/git_action.py +175 -0
  9. je_editor/git_client/git_cli.py +66 -0
  10. je_editor/pyside_ui/browser/browser_download_window.py +40 -4
  11. je_editor/pyside_ui/browser/browser_serach_lineedit.py +24 -0
  12. je_editor/pyside_ui/browser/browser_view.py +55 -6
  13. je_editor/pyside_ui/browser/browser_widget.py +62 -19
  14. je_editor/pyside_ui/browser/main_browser_widget.py +85 -0
  15. je_editor/pyside_ui/code/auto_save/auto_save_manager.py +33 -1
  16. je_editor/pyside_ui/code/auto_save/auto_save_thread.py +18 -5
  17. je_editor/pyside_ui/code/code_format/pep8_format.py +52 -7
  18. je_editor/pyside_ui/code/code_process/code_exec.py +118 -64
  19. je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +115 -53
  20. je_editor/pyside_ui/code/running_process_manager.py +18 -0
  21. je_editor/pyside_ui/code/shell_process/shell_exec.py +99 -60
  22. je_editor/pyside_ui/code/syntax/python_syntax.py +44 -9
  23. je_editor/pyside_ui/code/syntax/syntax_setting.py +39 -11
  24. je_editor/pyside_ui/code/textedit_code_result/code_record.py +33 -11
  25. je_editor/pyside_ui/code/variable_inspector/__init__.py +0 -0
  26. je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +172 -0
  27. je_editor/pyside_ui/dialog/ai_dialog/__init__.py +0 -0
  28. je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +71 -0
  29. je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +38 -4
  30. je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +32 -4
  31. je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +25 -2
  32. je_editor/pyside_ui/dialog/search_ui/search_error_box.py +27 -2
  33. je_editor/pyside_ui/dialog/search_ui/search_text_box.py +28 -3
  34. je_editor/pyside_ui/git_ui/__init__.py +0 -0
  35. je_editor/pyside_ui/git_ui/code_diff_compare/__init__.py +0 -0
  36. je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +90 -0
  37. je_editor/pyside_ui/git_ui/code_diff_compare/line_number_code_viewer.py +141 -0
  38. je_editor/pyside_ui/git_ui/code_diff_compare/multi_file_diff_viewer.py +88 -0
  39. je_editor/pyside_ui/git_ui/code_diff_compare/side_by_side_diff_widget.py +284 -0
  40. je_editor/pyside_ui/git_ui/git_client/__init__.py +0 -0
  41. je_editor/pyside_ui/git_ui/git_client/commit_table.py +65 -0
  42. je_editor/pyside_ui/git_ui/git_client/git_branch_tree_widget.py +156 -0
  43. je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +799 -0
  44. je_editor/pyside_ui/git_ui/git_client/graph_view.py +218 -0
  45. je_editor/pyside_ui/main_ui/ai_widget/__init__.py +0 -0
  46. je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +34 -0
  47. je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +36 -0
  48. je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +147 -0
  49. je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +84 -0
  50. je_editor/pyside_ui/main_ui/console_widget/__init__.py +0 -0
  51. je_editor/pyside_ui/main_ui/console_widget/console_gui.py +162 -0
  52. je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +84 -0
  53. je_editor/pyside_ui/main_ui/dock/destroy_dock.py +32 -1
  54. je_editor/pyside_ui/main_ui/editor/editor_widget.py +113 -23
  55. je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +33 -6
  56. je_editor/pyside_ui/main_ui/editor/process_input.py +42 -10
  57. je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +45 -10
  58. je_editor/pyside_ui/main_ui/main_editor.py +189 -49
  59. je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +50 -27
  60. je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +141 -30
  61. je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +67 -17
  62. je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +33 -3
  63. je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +39 -0
  64. je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +102 -40
  65. je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +53 -6
  66. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +47 -3
  67. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +45 -5
  68. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +41 -3
  69. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +21 -0
  70. je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +37 -11
  71. je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +42 -6
  72. je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +202 -27
  73. je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +66 -0
  74. je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +18 -1
  75. je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +32 -2
  76. je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +37 -10
  77. je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +39 -0
  78. je_editor/start_editor.py +25 -0
  79. je_editor/utils/encodings/python_encodings.py +100 -97
  80. je_editor/utils/exception/exception_tags.py +11 -11
  81. je_editor/utils/file/open/open_file.py +35 -19
  82. je_editor/utils/file/save/save_file.py +34 -13
  83. je_editor/utils/json/json_file.py +29 -14
  84. je_editor/utils/json_format/json_process.py +32 -1
  85. je_editor/utils/logging/loggin_instance.py +37 -7
  86. je_editor/utils/multi_language/english.py +102 -6
  87. je_editor/utils/multi_language/multi_language_wrapper.py +28 -3
  88. je_editor/utils/multi_language/traditional_chinese.py +101 -10
  89. je_editor/utils/redirect_manager/redirect_manager_class.py +49 -11
  90. je_editor/utils/venv_check/check_venv.py +37 -14
  91. {je_editor-0.0.202.dist-info → je_editor-0.0.228.dist-info}/METADATA +12 -6
  92. je_editor-0.0.228.dist-info/RECORD +140 -0
  93. {je_editor-0.0.202.dist-info → je_editor-0.0.228.dist-info}/WHEEL +1 -1
  94. je_editor-0.0.202.dist-info/RECORD +0 -108
  95. {je_editor-0.0.202.dist-info → je_editor-0.0.228.dist-info/licenses}/LICENSE +0 -0
  96. {je_editor-0.0.202.dist-info → je_editor-0.0.228.dist-info}/top_level.txt +0 -0
@@ -1,57 +1,88 @@
1
- from __future__ import annotations
1
+ from __future__ import annotations # 允許未來版本的型別註解功能 / Enable postponed evaluation of type annotations
2
2
 
3
- from typing import TYPE_CHECKING
3
+ from typing import \
4
+ TYPE_CHECKING # 用於避免循環匯入,僅在型別檢查時載入 / Used to avoid circular imports, only loaded during type checking
4
5
 
5
- from PySide6.QtCore import Qt
6
+ from PySide6.QtCore import Qt # Qt 核心模組 / Qt core module
6
7
  from PySide6.QtWidgets import QWidget, QLineEdit, QBoxLayout, QPushButton, QHBoxLayout
7
8
 
8
9
  from je_editor.utils.logging.loggin_instance import jeditor_logger
9
10
 
11
+ # 匯入 PySide6 的 GUI 元件 / Import GUI widgets from PySide6
12
+
13
+ # 專案內的日誌紀錄器 / Project's logger instance
14
+
10
15
  if TYPE_CHECKING:
11
16
  from je_editor.pyside_ui.main_ui.main_editor import EditorWidget
17
+ # 僅在型別檢查時匯入 EditorWidget,避免循環依賴 / Import only for type checking to avoid circular dependency
12
18
 
13
19
  from je_editor.utils.multi_language.multi_language_wrapper import language_wrapper
14
20
 
15
21
 
22
+ # 多語系支援工具 / Multi-language wrapper for UI text
23
+
24
+
16
25
  class ProcessInput(QWidget):
26
+ """
27
+ ProcessInput 是一個輸入視窗,允許使用者輸入指令並傳送到不同的子程序 (program/shell/debugger)。
28
+ ProcessInput is an input widget that allows users to send commands to different subprocesses.
29
+ """
17
30
 
18
31
  def __init__(self, main_window: EditorWidget, process_type: str = "debugger"):
32
+ # 初始化時記錄日誌 / Log initialization
19
33
  jeditor_logger.info("Init ProcessInput "
20
34
  f"main_window: {main_window} "
21
35
  f"process_type: {process_type}")
22
36
  super().__init__()
23
- # Attr
37
+
38
+ # 設定當視窗關閉時自動刪除資源
39
+ # Set attribute to delete widget on close
24
40
  self.setAttribute(Qt.WidgetAttribute.WA_DeleteOnClose)
25
- # UI setting
26
- self.main_window = main_window
27
- self.box_layout = QBoxLayout(QBoxLayout.Direction.TopToBottom)
28
- self.command_input = QLineEdit()
29
- self.send_command_button = QPushButton()
41
+
42
+ # === UI 設定 / UI Setup ===
43
+ self.main_window = main_window # 儲存主視窗參考 / Store reference to main window
44
+ self.box_layout = QBoxLayout(QBoxLayout.Direction.TopToBottom) # 垂直佈局 / Vertical layout
45
+ self.command_input = QLineEdit() # 輸入框 / Input field
46
+ self.send_command_button = QPushButton() # 傳送按鈕 / Send button
47
+
48
+ # 設定按鈕文字 (多語系) / Set button text (multi-language)
30
49
  self.send_command_button.setText(language_wrapper.language_word_dict.get("process_input_send_command"))
50
+
51
+ # 水平佈局,放置按鈕 / Horizontal layout for button
31
52
  self.box_h_layout = QHBoxLayout()
32
53
  self.box_h_layout.addWidget(self.send_command_button)
54
+
55
+ # 將元件加入主佈局 / Add widgets to main layout
33
56
  self.box_layout.addWidget(self.command_input)
34
57
  self.box_layout.addLayout(self.box_h_layout)
58
+
59
+ # 根據 process_type 設定不同的標題與功能 / Configure behavior based on process_type
35
60
  if process_type == "program":
36
61
  self.setWindowTitle(language_wrapper.language_word_dict.get("editor_program_input_title_label"))
37
62
  self.send_command_button.clicked.connect(self.program_send_command)
38
63
  elif process_type == "shell":
39
64
  self.setWindowTitle(language_wrapper.language_word_dict.get("editor_shell_input_title_label"))
40
65
  self.send_command_button.clicked.connect(self.shell_send_command)
41
- else:
66
+ else: # 預設為 debugger / Default: debugger
42
67
  self.setWindowTitle(language_wrapper.language_word_dict.get("editor_debugger_input_title_label"))
43
68
  self.send_command_button.clicked.connect(self.debugger_send_command)
69
+ # 切換主視窗的顯示頁面到 debugger 結果 / Switch main window tab to debugger result
44
70
  self.main_window.code_difference_result.setCurrentWidget(self.main_window.debugger_result)
71
+
72
+ # 設定主佈局 / Apply layout
45
73
  self.setLayout(self.box_layout)
46
74
 
75
+ # === Debugger 指令傳送 / Send command to debugger ===
47
76
  def debugger_send_command(self):
48
77
  jeditor_logger.info("EditorWidget debugger_send_command")
49
78
  if self.main_window.exec_python_debugger is not None:
50
79
  process_stdin = self.main_window.exec_python_debugger.process.stdin
51
80
  if process_stdin is not None:
81
+ # 將輸入框文字編碼後寫入子程序 stdin / Write encoded input to subprocess stdin
52
82
  process_stdin.write(self.command_input.text().encode() + b"\n")
53
83
  process_stdin.flush()
54
84
 
85
+ # === Shell 指令傳送 / Send command to shell ===
55
86
  def shell_send_command(self):
56
87
  jeditor_logger.info("EditorWidget shell_send_command")
57
88
  if self.main_window.exec_shell is not None:
@@ -60,6 +91,7 @@ class ProcessInput(QWidget):
60
91
  process_stdin.write(self.command_input.text().encode() + b"\n")
61
92
  process_stdin.flush()
62
93
 
94
+ # === Program 指令傳送 / Send command to program ===
63
95
  def program_send_command(self):
64
96
  jeditor_logger.info("EditorWidget program_send_command")
65
97
  if self.main_window.exec_program is not None:
@@ -1,43 +1,78 @@
1
- from __future__ import annotations
1
+ from __future__ import annotations # 啟用未來版本的型別註解功能 / Enable postponed evaluation of type annotations
2
2
 
3
- from typing import TYPE_CHECKING
3
+ from typing import TYPE_CHECKING # 僅在型別檢查時使用,避免循環匯入 / Used only for type checking to avoid circular imports
4
4
 
5
- from IPython.lib import guisupport
6
- from PySide6.QtWidgets import QWidget, QGridLayout
7
- from qtconsole.inprocess import QtInProcessKernelManager
8
- from qtconsole.rich_jupyter_widget import RichJupyterWidget
5
+ from IPython.lib import guisupport # 提供與 Qt GUI 整合的支援 / Provides support for integrating IPython with Qt GUI
6
+ from PySide6.QtWidgets import QWidget, QGridLayout # PySide6 視窗元件 / PySide6 widgets
7
+ from qtconsole.inprocess import QtInProcessKernelManager # 管理內嵌的 Jupyter kernel / Manages an in-process Jupyter kernel
8
+ from qtconsole.rich_jupyter_widget import RichJupyterWidget # Jupyter 富文本控制台元件 / Rich Jupyter console widget
9
9
 
10
- from je_editor.utils.logging.loggin_instance import jeditor_logger
10
+ from je_editor.utils.logging.loggin_instance import jeditor_logger # 專案內的日誌紀錄器 / Project logger
11
11
 
12
12
  if TYPE_CHECKING:
13
13
  from je_editor.pyside_ui.main_ui.main_editor import EditorMain
14
+ # 僅在型別檢查時匯入 EditorMain,避免循環依賴 / Import only for type checking to avoid circular dependency
14
15
 
15
16
 
16
17
  class IpythonWidget(QWidget):
18
+ """
19
+ IpythonWidget 類別
20
+ - 在 PySide6 GUI 中嵌入一個 Jupyter/IPython 控制台
21
+ - 提供互動式 Python 環境,方便在應用程式內直接執行程式碼
22
+ IpythonWidget class
23
+ - Embeds a Jupyter/IPython console inside a PySide6 GUI
24
+ - Provides an interactive Python environment within the application
25
+ """
17
26
 
18
27
  def __init__(self, main_window: EditorMain):
28
+ # 初始化時記錄日誌 / Log initialization
19
29
  jeditor_logger.info(f"Init IpythonWidget main_window: {main_window}")
20
30
  super().__init__()
31
+
32
+ # 建立網格佈局 / Create grid layout
21
33
  self.grid_layout = QGridLayout()
34
+
35
+ # 取得 Qt 應用程式實例 (Qt4 API,但可在 PySide6 中使用) / Get Qt application instance
22
36
  app = guisupport.get_app_qt4()
23
- self.kernel_manager = QtInProcessKernelManager()
24
- self.kernel_manager.start_kernel()
25
- self.kernel = self.kernel_manager.kernel
37
+
38
+ # === 建立並啟動 Jupyter Kernel / Create and start Jupyter kernel ===
39
+ self.kernel_manager = QtInProcessKernelManager() # 內嵌 kernel 管理器 / In-process kernel manager
40
+ self.kernel_manager.start_kernel() # 啟動 kernel / Start kernel
41
+ self.kernel = self.kernel_manager.kernel # 取得 kernel 實例 / Get kernel instance
42
+
43
+ # 建立 kernel client 並啟動通訊管道 / Create kernel client and start communication channels
26
44
  self.kernel_client = self.kernel_manager.client()
27
45
  self.kernel_client.start_channels()
46
+
47
+ # === 建立 Jupyter 控制台元件 / Create Jupyter console widget ===
28
48
  self.jupyter_widget = RichJupyterWidget()
29
49
  self.jupyter_widget.kernel_manager = self.kernel_manager
30
50
  self.jupyter_widget.kernel_client = self.kernel_client
51
+
52
+ # 將控制台加入佈局 (佔滿整個視窗) / Add console widget to layout (fill entire window)
31
53
  self.grid_layout.addWidget(self.jupyter_widget, 0, 0, -1, -1)
54
+
55
+ # 啟動 Qt 事件迴圈,讓 Jupyter 控制台能正常運作 / Start Qt event loop for Jupyter console
32
56
  guisupport.start_event_loop_qt4(app)
33
57
 
58
+ # 設定主佈局 / Apply layout
34
59
  self.setLayout(self.grid_layout)
35
60
 
36
61
  def close(self):
62
+ """
63
+ 覆寫 close 方法,確保關閉時正確釋放資源
64
+ Override close method to properly release resources
65
+ """
37
66
  jeditor_logger.info("IpythonWidget close")
67
+
68
+ # 停止 kernel client 的通訊管道 / Stop kernel client channels
38
69
  if self.kernel_client:
39
70
  self.kernel_client.stop_channels()
71
+
72
+ # 重啟並關閉 kernel,確保乾淨退出 / Restart and shutdown kernel for clean exit
40
73
  if self.kernel_manager:
41
74
  self.kernel_manager.restart_kernel()
42
75
  self.kernel_manager.shutdown_kernel()
76
+
77
+ # 呼叫父類別的 close 方法 / Call parent close method
43
78
  super().close()
@@ -4,38 +4,64 @@ import sys
4
4
  from pathlib import Path
5
5
  from typing import Dict, Type
6
6
 
7
+ # 匯入 Jedi 設定,用於 Python 自動補全與分析
8
+ # Import Jedi settings for Python auto-completion and analysis
7
9
  import jedi.settings
10
+ # 匯入 PySide6 (Qt for Python) 的核心模組
11
+ # Import PySide6 core modules
8
12
  from PySide6.QtCore import QTimer, QEvent
9
- from PySide6.QtGui import QFontDatabase, QIcon, Qt
13
+ from PySide6.QtGui import QFontDatabase, QIcon, Qt, QTextCharFormat
10
14
  from PySide6.QtWidgets import QMainWindow, QWidget, QTabWidget
11
- from frontengine import FrontEngineMainUI
15
+ # 匯入 Qt Material 主題工具
16
+ # Import Qt Material style tools
12
17
  from qt_material import QtStyleTools
13
18
 
19
+ # 匯入專案內部模組 (自訂 UI 與功能)
20
+ # Import project-specific modules (custom UI and features)
14
21
  from je_editor.pyside_ui.browser.browser_widget import BrowserWidget
22
+ from je_editor.pyside_ui.browser.main_browser_widget import MainBrowserWidget
15
23
  from je_editor.pyside_ui.code.auto_save.auto_save_manager import init_new_auto_save_thread, file_is_open_manager_dict
16
24
  from je_editor.pyside_ui.main_ui.editor.editor_widget import EditorWidget
17
25
  from je_editor.pyside_ui.main_ui.menu.set_menu_bar import set_menu_bar
18
- from je_editor.pyside_ui.main_ui.save_settings.user_color_setting_file import write_user_color_setting, \
19
- read_user_color_setting, update_actually_color_dict
20
- from je_editor.pyside_ui.main_ui.save_settings.user_setting_file import user_setting_dict, read_user_setting, \
26
+ from je_editor.pyside_ui.main_ui.save_settings.user_color_setting_file import (
27
+ write_user_color_setting,
28
+ read_user_color_setting,
29
+ update_actually_color_dict,
30
+ actually_color_dict
31
+ )
32
+ from je_editor.pyside_ui.main_ui.save_settings.user_setting_file import (
33
+ user_setting_dict,
34
+ read_user_setting,
21
35
  write_user_setting
36
+ )
22
37
  from je_editor.pyside_ui.main_ui.system_tray.extend_system_tray import ExtendSystemTray
23
38
  from je_editor.utils.file.open.open_file import read_file
24
39
  from je_editor.utils.logging.loggin_instance import jeditor_logger
25
40
  from je_editor.utils.multi_language.multi_language_wrapper import language_wrapper
26
41
  from je_editor.utils.redirect_manager.redirect_manager_class import redirect_manager_instance
27
42
 
43
+ # 定義一個字典,用來存放可擴充的 Tab (標籤頁)
44
+ # Define a dictionary to store extendable tabs
28
45
  EDITOR_EXTEND_TAB: Dict[str, Type[QWidget]] = {}
29
46
 
30
47
 
31
48
  class EditorMain(QMainWindow, QtStyleTools):
49
+ """
50
+ 主編輯器視窗類別
51
+ Main editor window class
52
+ 繼承 QMainWindow 與 QtStyleTools
53
+ """
32
54
 
33
55
  def __init__(self, debug_mode: bool = False, show_system_tray_ray: bool = False):
56
+ # 初始化時記錄 log
57
+ # Log initialization
34
58
  jeditor_logger.info(f"Init EditorMain "
35
59
  f"debug_mode: {debug_mode} "
36
60
  f"show_system_tray_ray: {show_system_tray_ray}")
37
61
  super(EditorMain, self).__init__()
38
- # Init variable
62
+
63
+ # 初始化變數
64
+ # Initialize variables
39
65
  self.file_menu = None
40
66
  self.code_result = None
41
67
  self.code_edit = None
@@ -45,79 +71,130 @@ class EditorMain(QMainWindow, QtStyleTools):
45
71
  self.font_menu = None
46
72
  self.working_dir = None
47
73
  self.show_system_tray_ray = show_system_tray_ray
48
- # Self attr
49
- # Read user setting first
74
+
75
+ # 讀取使用者設定
76
+ # Read user settings
50
77
  read_user_setting()
51
- # Set language
78
+
79
+ # 設定語言 (多語系支援)
80
+ # Set language (multi-language support)
52
81
  language_wrapper.reset_language(user_setting_dict.get("language", "English"))
53
- # Jedi run on thread safe
82
+
83
+ # Jedi 設定:關閉快取解析器,避免執行緒問題
84
+ # Jedi settings: disable fast parser for thread safety
54
85
  jedi.settings.fast_parser = False
55
- # Jedi only show right case_insensitive
56
- jedi.settings.case_insensitive_completion = False
57
- # Project compiler if user not choose this will use which to find
86
+ jedi.settings.case_insensitive_completion = False # 關閉大小寫不敏感補全 / Disable case-insensitive completion
87
+
88
+ # Python 編譯器 (可由使用者指定)
89
+ # Python compiler (can be set by user)
58
90
  self.python_compiler = None
91
+
92
+ # 除錯模式
59
93
  # Debug mode
60
94
  self.debug_mode: bool = debug_mode
61
- # Windows setup
95
+
96
+ # Windows 系統專用:設定應用程式 ID
97
+ # Windows only: set application ID
62
98
  self.id = language_wrapper.language_word_dict.get("application_name")
63
99
  if sys.platform in ["win32", "cygwin", "msys"]:
64
100
  from ctypes import windll
65
101
  windll.shell32.SetCurrentProcessExplicitAppUserModelID(self.id)
66
- # set python buffered
102
+
103
+ # 設定 Python 輸出不緩衝
104
+ # Set Python output unbuffered
67
105
  os.environ["PYTHONUNBUFFERED"] = "1"
68
- # Auto save thread
106
+
107
+ # 自動儲存執行緒
108
+ # Auto-save thread
69
109
  self.auto_save_thread = None
70
- # Encoding
110
+
111
+ # 預設編碼
112
+ # Default encoding
71
113
  self.encoding = "utf-8"
114
+
115
+ # 讀取使用者顏色設定
116
+ # Read user color settings
72
117
  read_user_color_setting()
73
- # Font
118
+
119
+ # 字型資料庫
120
+ # Font database
74
121
  self.font_database = QFontDatabase()
75
- # TabWidget
122
+
123
+ # 建立 TabWidget (多分頁編輯器)
124
+ # Create TabWidget (multi-tab editor)
76
125
  self.tab_widget = QTabWidget()
77
- self.tab_widget.setTabsClosable(True)
126
+ self.tab_widget.setTabsClosable(True) # 可關閉分頁 / Tabs closable
78
127
  self.tab_widget.setAttribute(Qt.WidgetAttribute.WA_AlwaysShowToolTips, on=False)
79
128
  self.tab_widget.tabCloseRequested.connect(self.close_tab)
80
- # Timer to redirect error or message
129
+
130
+ # 建立計時器,用來處理訊息重導 (stdout/stderr)
131
+ # Timer for redirecting messages (stdout/stderr)
81
132
  self.redirect_timer = QTimer(self)
82
133
  self.redirect_timer.setInterval(10)
83
134
  self.redirect_timer.start()
135
+
136
+ # 設定視窗標題與提示
137
+ # Set window title and tooltip
84
138
  self.setWindowTitle(language_wrapper.language_word_dict.get("application_name"))
85
139
  self.setToolTip(language_wrapper.language_word_dict.get("application_name"))
140
+
141
+ # 設定選單列
142
+ # Set menu bar
86
143
  set_menu_bar(self)
87
- # Set Icon
144
+
145
+ # 設定應用程式圖示
146
+ # Set application icon
88
147
  self.icon_path = Path(os.getcwd() + "/je_driver_icon.ico")
89
148
  self.icon = QIcon(str(self.icon_path))
90
149
  if self.icon.isNull() is False:
91
150
  self.setWindowIcon(self.icon)
151
+ # 如果系統支援系統匣,則顯示圖示
152
+ # Show system tray icon if available
92
153
  if ExtendSystemTray.isSystemTrayAvailable() and self.show_system_tray_ray:
93
154
  self.system_tray = ExtendSystemTray(main_window=self)
94
155
  self.system_tray.setIcon(self.icon)
95
156
  self.system_tray.setVisible(True)
96
157
  self.system_tray.show()
97
158
  self.system_tray.setToolTip(language_wrapper.language_word_dict.get("application_name"))
98
- # Put Redirect on last to trace exception
159
+
160
+ # 設定輸出重導 (stdout/stderr)
161
+ # Setup output redirection (stdout/stderr)
99
162
  redirect_manager_instance.restore_std()
100
163
  redirect_manager_instance.set_redirect()
101
- # Timer to redirect error or message
164
+
165
+ # 再次設定計時器,定期檢查輸出
166
+ # Setup timer again to check redirected output
102
167
  self.redirect_timer = QTimer(self)
103
168
  self.redirect_timer.setInterval(10)
104
169
  self.redirect_timer.timeout.connect(self.redirect)
105
170
  self.redirect_timer.start()
106
- # TAB Add
171
+
172
+ # 建立主要分頁:編輯器與瀏覽器
173
+ # Create main tabs: editor and browser
174
+ main_browser_widget = MainBrowserWidget()
107
175
  self.tab_widget.addTab(EditorWidget(self), language_wrapper.language_word_dict.get("tab_name_editor"))
108
- self.tab_widget.addTab(
109
- FrontEngineMainUI(show_system_tray_ray=False, redirect_output=False),
110
- language_wrapper.language_word_dict.get("tab_name_frontengine"))
111
- self.tab_widget.addTab(BrowserWidget(), language_wrapper.language_word_dict.get("tab_name_web_browser"))
112
- self.tab_widget.addTab(
113
- BrowserWidget(start_url="https://stackoverflow.com/", search_prefix="https://stackoverflow.com/search?q="),
114
- language_wrapper.language_word_dict.get("tab_menu_stackoverflow_tab_name"))
176
+ self.tab_widget.addTab(main_browser_widget, language_wrapper.language_word_dict.get("tab_name_web_browser"))
177
+
178
+ # 預設新增一個 StackOverflow 瀏覽分頁
179
+ # Add a default StackOverflow browser tab
180
+ main_browser_widget.add_browser_tab(
181
+ BrowserWidget(start_url="https://stackoverflow.com/", search_prefix="https://stackoverflow.com/search?q="))
182
+
183
+ # 加入擴充的自訂分頁
184
+ # Add extended custom tabs
115
185
  for widget_name, widget in EDITOR_EXTEND_TAB.items():
116
186
  self.tab_widget.addTab(widget(), widget_name)
187
+
188
+ # 設定中央元件為 TabWidget
189
+ # Set central widget as TabWidget
117
190
  self.setCentralWidget(self.tab_widget)
118
- # Read Setting
191
+
192
+ # 啟動時讀取設定
193
+ # Load startup settings
119
194
  self.startup_setting()
120
- # If debug open 10s and close
195
+
196
+ # 如果是 debug 模式,10 秒後自動關閉
197
+ # If debug mode, auto-close after 10 seconds
121
198
  if self.debug_mode:
122
199
  close_timer = QTimer(self)
123
200
  close_timer.setInterval(10000)
@@ -125,55 +202,91 @@ class EditorMain(QMainWindow, QtStyleTools):
125
202
  close_timer.start()
126
203
 
127
204
  def clear_code_result(self):
205
+ """
206
+ 清除目前編輯器的輸出結果
207
+ Clear the current editor's output result
208
+ """
128
209
  jeditor_logger.info(f"EditorMain clear_code_result")
129
210
  widget = self.tab_widget.currentWidget()
130
211
  if isinstance(widget, EditorWidget):
131
212
  widget.code_result.clear()
132
213
 
133
214
  def redirect(self) -> None:
215
+ """
216
+ 將 stdout/stderr 的訊息導入到編輯器的輸出區域
217
+ Redirect stdout/stderr messages into the editor's output area
218
+ """
134
219
  jeditor_logger.info(f"EditorMain redirect")
220
+ # 遍歷所有分頁 (Tab),尋找 EditorWidget
221
+ # Iterate through all tabs to find EditorWidget
135
222
  for code_editor in range(self.tab_widget.count()):
136
223
  widget = self.tab_widget.widget(code_editor)
137
224
  if isinstance(widget, EditorWidget):
138
- # Pull out redirect text and put text in code result area
225
+ # stdout 輸出處理
226
+ # Handle stdout messages
139
227
  if not redirect_manager_instance.std_out_queue.empty():
140
228
  output_message = redirect_manager_instance.std_out_queue.get_nowait()
141
229
  output_message = str(output_message).strip()
142
230
  if output_message:
143
- widget.code_result.append(output_message)
144
- widget.code_result.setTextColor(Qt.GlobalColor.red)
231
+ text_cursor = self.code_result.textCursor()
232
+ text_format = QTextCharFormat()
233
+ # 設定正常輸出顏色
234
+ # Set normal output color
235
+ text_format.setForeground(actually_color_dict.get("normal_output_color"))
236
+ text_cursor.insertText(output_message, text_format)
237
+ text_cursor.insertBlock()
238
+
239
+ # stderr 錯誤輸出處理
240
+ # Handle stderr messages
145
241
  if not redirect_manager_instance.std_err_queue.empty():
146
242
  error_message = redirect_manager_instance.std_err_queue.get_nowait()
147
243
  error_message = str(error_message).strip()
148
244
  if error_message:
149
- widget.code_result.append(error_message)
150
- widget.code_result.setTextColor(Qt.GlobalColor.black)
151
- break
245
+ text_cursor = self.code_result.textCursor()
246
+ text_format = QTextCharFormat()
247
+ # 設定錯誤輸出顏色
248
+ # Set error output color
249
+ text_format.setForeground(actually_color_dict.get("error_output_color"))
250
+ text_cursor.insertText(error_message, text_format)
251
+ text_cursor.insertBlock()
252
+ break # 找到第一個 EditorWidget 就結束迴圈 / Stop after first EditorWidget found
152
253
 
153
254
  def startup_setting(self) -> None:
255
+ """
256
+ 啟動時套用使用者設定 (字型、樣式、上次開啟的檔案)
257
+ Apply user settings on startup (fonts, styles, last opened file)
258
+ """
154
259
  jeditor_logger.info(f"EditorMain startup_setting")
155
- # Set font and font size, then try to open last edit file
260
+ # 設定 UI 字型與大小
261
+ # Set UI font and size
156
262
  self.setStyleSheet(
157
263
  f"font-size: {user_setting_dict.get('ui_font_size', 12)}pt;"
158
264
  f"font-family: {user_setting_dict.get('ui_font', 'Lato')};"
159
265
  )
160
- # User setting
266
+
267
+ # 套用到每個編輯器分頁
268
+ # Apply settings to each editor tab
161
269
  for code_editor_count in range(self.tab_widget.count()):
162
270
  widget = self.tab_widget.widget(code_editor_count)
163
271
  if isinstance(widget, EditorWidget):
164
- # Font size
272
+ # 編輯區字型
273
+ # Font for code editor
165
274
  widget.code_edit.setStyleSheet(
166
275
  f"font-size: {user_setting_dict.get('font_size', 12)}pt;"
167
276
  f"font-family: {user_setting_dict.get('font', 'Lato')};"
168
277
  )
169
- # Font
278
+ # 輸出區字型
279
+ # Font for output area
170
280
  widget.code_result.setStyleSheet(
171
281
  f"font-size: {user_setting_dict.get('font_size', 12)}pt;"
172
282
  f"font-family: {user_setting_dict.get('font', 'Lato')};"
173
283
  )
174
- # Default compiler
284
+ # 預設 Python 編譯器
285
+ # Default Python compiler
175
286
  self.python_compiler = user_setting_dict.get("python_compiler", None)
176
- # Last edit file
287
+
288
+ # 嘗試開啟上次編輯的檔案
289
+ # Try to open last edited file
177
290
  last_file = user_setting_dict.get("last_file", None)
178
291
  if last_file is not None:
179
292
  last_file_path = pathlib.Path(last_file)
@@ -185,32 +298,51 @@ class EditorMain(QMainWindow, QtStyleTools):
185
298
  file_is_open_manager_dict.update({str(last_file_path): str(last_file_path.name)})
186
299
  widget.rename_self_tab()
187
300
 
188
- # Style
301
+ # 套用 UI 樣式 (主題)
302
+ # Apply UI stylesheet (theme)
189
303
  self.apply_stylesheet(self, user_setting_dict.get("ui_style", "dark_amber.xml"))
190
- # Color
304
+ # 更新顏色設定
305
+ # Update color settings
191
306
  update_actually_color_dict()
192
307
 
193
308
  def go_to_new_tab(self, file_path: Path):
309
+ """
310
+ 開啟新分頁並載入檔案
311
+ Open a new tab and load a file
312
+ """
194
313
  jeditor_logger.info(f"EditorMain go_to_new_tab file_path: {file_path}")
195
314
  if file_is_open_manager_dict.get(str(file_path), None) is None:
315
+ # 建立新的編輯器分頁
316
+ # Create a new editor tab
196
317
  editor_widget = EditorWidget(self)
197
318
  self.tab_widget.addTab(
198
319
  editor_widget,
199
320
  f"{language_wrapper.language_word_dict.get('tab_menu_editor_tab_name')} "
200
- f"{self.tab_widget.count()}")
321
+ f"{self.tab_widget.count()}"
322
+ )
201
323
  self.tab_widget.setCurrentWidget(editor_widget)
202
324
  editor_widget.open_an_file(file_path)
203
325
  else:
326
+ # 如果檔案已開啟,直接切換到該分頁
327
+ # If file already opened, switch to that tab
204
328
  widget: QWidget = self.tab_widget.findChild(EditorWidget, str(file_path))
205
329
  self.tab_widget.setCurrentWidget(widget)
206
330
 
207
331
  def closeEvent(self, event) -> None:
332
+ """
333
+ 視窗關閉事件:儲存使用者設定
334
+ Window close event: save user settings
335
+ """
208
336
  jeditor_logger.info("EditorMain closeEvent")
209
337
  write_user_setting()
210
338
  write_user_color_setting()
211
339
  super().closeEvent(event)
212
340
 
213
341
  def event(self, event: QEvent) -> bool:
342
+ """
343
+ 事件處理:忽略 ToolTip 類型事件
344
+ Event handler: ignore ToolTip events
345
+ """
214
346
  jeditor_logger.info(f"EditorMain event: {event}")
215
347
  if event.type() == QEvent.Type.ToolTip:
216
348
  event.ignore()
@@ -219,6 +351,10 @@ class EditorMain(QMainWindow, QtStyleTools):
219
351
  return super().event(event)
220
352
 
221
353
  def close_tab(self, index: int):
354
+ """
355
+ 關閉指定索引的分頁
356
+ Close tab at given index
357
+ """
222
358
  widget = self.tab_widget.widget(index)
223
359
  if widget:
224
360
  widget.close()
@@ -226,4 +362,8 @@ class EditorMain(QMainWindow, QtStyleTools):
226
362
 
227
363
  @classmethod
228
364
  def debug_close(cls):
365
+ """
366
+ 除錯模式下自動關閉程式
367
+ Auto-close the program in debug mode
368
+ """
229
369
  sys.exit(0)