je-editor 0.0.223__py3-none-any.whl → 0.0.224__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.

Potentially problematic release.


This version of je-editor might be problematic. Click here for more details.

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