je-editor 0.0.104__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 (151) hide show
  1. je_editor/__init__.py +26 -21
  2. je_editor/__main__.py +1 -1
  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/commit_graph.py +77 -0
  7. je_editor/git_client/git_action.py +175 -0
  8. je_editor/git_client/git_cli.py +66 -0
  9. je_editor/pyside_ui/browser/browser_download_window.py +75 -0
  10. je_editor/pyside_ui/browser/browser_serach_lineedit.py +51 -0
  11. je_editor/pyside_ui/browser/browser_view.py +87 -0
  12. je_editor/pyside_ui/browser/browser_widget.py +103 -0
  13. je_editor/pyside_ui/browser/main_browser_widget.py +85 -0
  14. je_editor/pyside_ui/code/auto_save/auto_save_manager.py +60 -0
  15. je_editor/pyside_ui/code/auto_save/auto_save_thread.py +59 -0
  16. je_editor/pyside_ui/code/code_format/pep8_format.py +130 -0
  17. je_editor/pyside_ui/code/code_process/code_exec.py +267 -0
  18. je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +412 -0
  19. je_editor/pyside_ui/code/running_process_manager.py +48 -0
  20. je_editor/pyside_ui/code/shell_process/shell_exec.py +236 -0
  21. je_editor/pyside_ui/code/syntax/python_syntax.py +99 -0
  22. je_editor/pyside_ui/code/syntax/syntax_setting.py +95 -0
  23. je_editor/pyside_ui/code/textedit_code_result/code_record.py +75 -0
  24. je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +172 -0
  25. je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +71 -0
  26. je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +68 -0
  27. je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +111 -0
  28. je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +67 -0
  29. je_editor/pyside_ui/dialog/search_ui/search_error_box.py +49 -0
  30. je_editor/pyside_ui/dialog/search_ui/search_text_box.py +49 -0
  31. je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +90 -0
  32. je_editor/pyside_ui/git_ui/code_diff_compare/line_number_code_viewer.py +141 -0
  33. je_editor/pyside_ui/git_ui/code_diff_compare/multi_file_diff_viewer.py +88 -0
  34. je_editor/pyside_ui/git_ui/code_diff_compare/side_by_side_diff_widget.py +284 -0
  35. je_editor/pyside_ui/git_ui/git_client/commit_table.py +65 -0
  36. je_editor/pyside_ui/git_ui/git_client/git_branch_tree_widget.py +156 -0
  37. je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +799 -0
  38. je_editor/pyside_ui/git_ui/git_client/graph_view.py +218 -0
  39. je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +34 -0
  40. je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +36 -0
  41. je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +147 -0
  42. je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +84 -0
  43. je_editor/pyside_ui/main_ui/console_widget/console_gui.py +162 -0
  44. je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +84 -0
  45. je_editor/pyside_ui/main_ui/dock/__init__.py +0 -0
  46. je_editor/pyside_ui/main_ui/dock/destroy_dock.py +50 -0
  47. je_editor/pyside_ui/main_ui/editor/__init__.py +0 -0
  48. je_editor/pyside_ui/main_ui/editor/editor_widget.py +301 -0
  49. je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +70 -0
  50. je_editor/pyside_ui/main_ui/editor/process_input.py +101 -0
  51. je_editor/pyside_ui/main_ui/ipython_widget/__init__.py +0 -0
  52. je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +78 -0
  53. je_editor/pyside_ui/main_ui/main_editor.py +369 -0
  54. je_editor/pyside_ui/main_ui/menu/__init__.py +0 -0
  55. je_editor/pyside_ui/main_ui/menu/check_style_menu/__init__.py +0 -0
  56. je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +104 -0
  57. je_editor/pyside_ui/main_ui/menu/dock_menu/__init__.py +0 -0
  58. je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +208 -0
  59. je_editor/pyside_ui/main_ui/menu/file_menu/__init__.py +0 -0
  60. je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +186 -0
  61. je_editor/pyside_ui/main_ui/menu/help_menu/__init__.py +0 -0
  62. je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +100 -0
  63. je_editor/pyside_ui/main_ui/menu/language_menu/__init__.py +0 -0
  64. je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +89 -0
  65. je_editor/pyside_ui/main_ui/menu/python_env_menu/__init__.py +0 -0
  66. je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +238 -0
  67. je_editor/pyside_ui/main_ui/menu/run_menu/__init__.py +0 -0
  68. je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +160 -0
  69. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/__init__.py +0 -0
  70. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +109 -0
  71. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +101 -0
  72. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +98 -0
  73. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +41 -0
  74. je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +63 -0
  75. je_editor/pyside_ui/main_ui/menu/style_menu/__init__.py +0 -0
  76. je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +73 -0
  77. je_editor/pyside_ui/main_ui/menu/tab_menu/__init__.py +0 -0
  78. je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +275 -0
  79. je_editor/pyside_ui/main_ui/menu/text_menu/__init__.py +0 -0
  80. je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +135 -0
  81. je_editor/pyside_ui/main_ui/save_settings/__init__.py +0 -0
  82. je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +33 -0
  83. je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +103 -0
  84. je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +58 -0
  85. je_editor/pyside_ui/main_ui/system_tray/__init__.py +0 -0
  86. je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +90 -0
  87. je_editor/start_editor.py +32 -8
  88. je_editor/utils/encodings/python_encodings.py +100 -97
  89. je_editor/utils/exception/exception_tags.py +11 -11
  90. je_editor/utils/file/open/open_file.py +38 -22
  91. je_editor/utils/file/save/save_file.py +40 -16
  92. je_editor/utils/json/json_file.py +36 -15
  93. je_editor/utils/json_format/json_process.py +38 -2
  94. je_editor/utils/logging/__init__.py +0 -0
  95. je_editor/utils/logging/loggin_instance.py +57 -0
  96. je_editor/utils/multi_language/__init__.py +0 -0
  97. je_editor/utils/multi_language/english.py +221 -0
  98. je_editor/utils/multi_language/multi_language_wrapper.py +54 -0
  99. je_editor/utils/multi_language/traditional_chinese.py +214 -0
  100. je_editor/utils/redirect_manager/redirect_manager_class.py +67 -25
  101. je_editor/utils/venv_check/__init__.py +0 -0
  102. je_editor/utils/venv_check/check_venv.py +51 -0
  103. je_editor-0.0.228.dist-info/METADATA +99 -0
  104. je_editor-0.0.228.dist-info/RECORD +140 -0
  105. {je_editor-0.0.104.dist-info → je_editor-0.0.228.dist-info}/WHEEL +1 -1
  106. {je_editor-0.0.104.dist-info → je_editor-0.0.228.dist-info/licenses}/LICENSE +1 -1
  107. je_editor/pyside_ui/auto_save/auto_save_thread.py +0 -34
  108. je_editor/pyside_ui/code_editor/code_edit_plaintext.py +0 -143
  109. je_editor/pyside_ui/code_process/code_exec.py +0 -190
  110. je_editor/pyside_ui/code_result/code_record.py +0 -39
  111. je_editor/pyside_ui/colors/global_color.py +0 -4
  112. je_editor/pyside_ui/file_dialog/open_file_dialog.py +0 -27
  113. je_editor/pyside_ui/file_dialog/save_file_dialog.py +0 -24
  114. je_editor/pyside_ui/main_ui/editor_main_ui/main_editor.py +0 -183
  115. je_editor/pyside_ui/main_ui_setting/ui_setting.py +0 -36
  116. je_editor/pyside_ui/menu/menu_bar/check_style_menu/build_check_style_menu.py +0 -44
  117. je_editor/pyside_ui/menu/menu_bar/file_menu/build_file_menu.py +0 -30
  118. je_editor/pyside_ui/menu/menu_bar/help_menu/build_help_menu.py +0 -39
  119. je_editor/pyside_ui/menu/menu_bar/run_menu/build_run_menu.py +0 -102
  120. je_editor/pyside_ui/menu/menu_bar/set_menu_bar.py +0 -24
  121. je_editor/pyside_ui/menu/menu_bar/venv_menu/build_venv_menu.py +0 -74
  122. je_editor/pyside_ui/search_ui/search_error_box.py +0 -20
  123. je_editor/pyside_ui/search_ui/search_text_box.py +0 -20
  124. je_editor/pyside_ui/shell_process/shell_exec.py +0 -157
  125. je_editor/pyside_ui/syntax/python_syntax.py +0 -99
  126. je_editor/pyside_ui/treeview/project_treeview/set_project_treeview.py +0 -47
  127. je_editor/pyside_ui/user_setting/user_setting_file.py +0 -23
  128. je_editor-0.0.104.dist-info/METADATA +0 -84
  129. je_editor-0.0.104.dist-info/RECORD +0 -69
  130. /je_editor/{pyside_ui/auto_save → code_scan}/__init__.py +0 -0
  131. /je_editor/{pyside_ui/code_editor → git_client}/__init__.py +0 -0
  132. /je_editor/pyside_ui/{code_process → browser}/__init__.py +0 -0
  133. /je_editor/pyside_ui/{code_result → code}/__init__.py +0 -0
  134. /je_editor/pyside_ui/{colors → code/auto_save}/__init__.py +0 -0
  135. /je_editor/pyside_ui/{file_dialog → code/code_format}/__init__.py +0 -0
  136. /je_editor/pyside_ui/{main_ui/editor_main_ui → code/code_process}/__init__.py +0 -0
  137. /je_editor/pyside_ui/{main_ui_setting → code/plaintext_code_edit}/__init__.py +0 -0
  138. /je_editor/pyside_ui/{menu → code/shell_process}/__init__.py +0 -0
  139. /je_editor/pyside_ui/{menu/menu_bar → code/syntax}/__init__.py +0 -0
  140. /je_editor/pyside_ui/{menu/menu_bar/check_style_menu → code/textedit_code_result}/__init__.py +0 -0
  141. /je_editor/pyside_ui/{menu/menu_bar/file_menu → code/variable_inspector}/__init__.py +0 -0
  142. /je_editor/pyside_ui/{menu/menu_bar/help_menu → dialog}/__init__.py +0 -0
  143. /je_editor/pyside_ui/{menu/menu_bar/run_menu → dialog/ai_dialog}/__init__.py +0 -0
  144. /je_editor/pyside_ui/{menu/menu_bar/venv_menu → dialog/file_dialog}/__init__.py +0 -0
  145. /je_editor/pyside_ui/{search_ui → dialog/search_ui}/__init__.py +0 -0
  146. /je_editor/pyside_ui/{shell_process → git_ui}/__init__.py +0 -0
  147. /je_editor/pyside_ui/{syntax → git_ui/code_diff_compare}/__init__.py +0 -0
  148. /je_editor/pyside_ui/{treeview → git_ui/git_client}/__init__.py +0 -0
  149. /je_editor/pyside_ui/{treeview/project_treeview → main_ui/ai_widget}/__init__.py +0 -0
  150. /je_editor/pyside_ui/{user_setting → main_ui/console_widget}/__init__.py +0 -0
  151. {je_editor-0.0.104.dist-info → je_editor-0.0.228.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,78 @@
1
+ from __future__ import annotations # 啟用未來版本的型別註解功能 / Enable postponed evaluation of type annotations
2
+
3
+ from typing import TYPE_CHECKING # 僅在型別檢查時使用,避免循環匯入 / Used only for type checking to avoid circular imports
4
+
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
+
10
+ from je_editor.utils.logging.loggin_instance import jeditor_logger # 專案內的日誌紀錄器 / Project logger
11
+
12
+ if TYPE_CHECKING:
13
+ from je_editor.pyside_ui.main_ui.main_editor import EditorMain
14
+ # 僅在型別檢查時匯入 EditorMain,避免循環依賴 / Import only for type checking to avoid circular dependency
15
+
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
+ """
26
+
27
+ def __init__(self, main_window: EditorMain):
28
+ # 初始化時記錄日誌 / Log initialization
29
+ jeditor_logger.info(f"Init IpythonWidget main_window: {main_window}")
30
+ super().__init__()
31
+
32
+ # 建立網格佈局 / Create grid layout
33
+ self.grid_layout = QGridLayout()
34
+
35
+ # 取得 Qt 應用程式實例 (Qt4 API,但可在 PySide6 中使用) / Get Qt application instance
36
+ app = guisupport.get_app_qt4()
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
44
+ self.kernel_client = self.kernel_manager.client()
45
+ self.kernel_client.start_channels()
46
+
47
+ # === 建立 Jupyter 控制台元件 / Create Jupyter console widget ===
48
+ self.jupyter_widget = RichJupyterWidget()
49
+ self.jupyter_widget.kernel_manager = self.kernel_manager
50
+ self.jupyter_widget.kernel_client = self.kernel_client
51
+
52
+ # 將控制台加入佈局 (佔滿整個視窗) / Add console widget to layout (fill entire window)
53
+ self.grid_layout.addWidget(self.jupyter_widget, 0, 0, -1, -1)
54
+
55
+ # 啟動 Qt 事件迴圈,讓 Jupyter 控制台能正常運作 / Start Qt event loop for Jupyter console
56
+ guisupport.start_event_loop_qt4(app)
57
+
58
+ # 設定主佈局 / Apply layout
59
+ self.setLayout(self.grid_layout)
60
+
61
+ def close(self):
62
+ """
63
+ 覆寫 close 方法,確保關閉時正確釋放資源
64
+ Override close method to properly release resources
65
+ """
66
+ jeditor_logger.info("IpythonWidget close")
67
+
68
+ # 停止 kernel client 的通訊管道 / Stop kernel client channels
69
+ if self.kernel_client:
70
+ self.kernel_client.stop_channels()
71
+
72
+ # 重啟並關閉 kernel,確保乾淨退出 / Restart and shutdown kernel for clean exit
73
+ if self.kernel_manager:
74
+ self.kernel_manager.restart_kernel()
75
+ self.kernel_manager.shutdown_kernel()
76
+
77
+ # 呼叫父類別的 close 方法 / Call parent close method
78
+ super().close()
@@ -0,0 +1,369 @@
1
+ import os
2
+ import pathlib
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Dict, Type
6
+
7
+ # 匯入 Jedi 設定,用於 Python 自動補全與分析
8
+ # Import Jedi settings for Python auto-completion and analysis
9
+ import jedi.settings
10
+ # 匯入 PySide6 (Qt for Python) 的核心模組
11
+ # Import PySide6 core modules
12
+ from PySide6.QtCore import QTimer, QEvent
13
+ from PySide6.QtGui import QFontDatabase, QIcon, Qt, QTextCharFormat
14
+ from PySide6.QtWidgets import QMainWindow, QWidget, QTabWidget
15
+ # 匯入 Qt Material 主題工具
16
+ # Import Qt Material style tools
17
+ from qt_material import QtStyleTools
18
+
19
+ # 匯入專案內部模組 (自訂 UI 與功能)
20
+ # Import project-specific modules (custom UI and features)
21
+ from je_editor.pyside_ui.browser.browser_widget import BrowserWidget
22
+ from je_editor.pyside_ui.browser.main_browser_widget import MainBrowserWidget
23
+ from je_editor.pyside_ui.code.auto_save.auto_save_manager import init_new_auto_save_thread, file_is_open_manager_dict
24
+ from je_editor.pyside_ui.main_ui.editor.editor_widget import EditorWidget
25
+ from je_editor.pyside_ui.main_ui.menu.set_menu_bar import set_menu_bar
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,
35
+ write_user_setting
36
+ )
37
+ from je_editor.pyside_ui.main_ui.system_tray.extend_system_tray import ExtendSystemTray
38
+ from je_editor.utils.file.open.open_file import read_file
39
+ from je_editor.utils.logging.loggin_instance import jeditor_logger
40
+ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapper
41
+ from je_editor.utils.redirect_manager.redirect_manager_class import redirect_manager_instance
42
+
43
+ # 定義一個字典,用來存放可擴充的 Tab (標籤頁)
44
+ # Define a dictionary to store extendable tabs
45
+ EDITOR_EXTEND_TAB: Dict[str, Type[QWidget]] = {}
46
+
47
+
48
+ class EditorMain(QMainWindow, QtStyleTools):
49
+ """
50
+ 主編輯器視窗類別
51
+ Main editor window class
52
+ 繼承 QMainWindow 與 QtStyleTools
53
+ """
54
+
55
+ def __init__(self, debug_mode: bool = False, show_system_tray_ray: bool = False):
56
+ # 初始化時記錄 log
57
+ # Log initialization
58
+ jeditor_logger.info(f"Init EditorMain "
59
+ f"debug_mode: {debug_mode} "
60
+ f"show_system_tray_ray: {show_system_tray_ray}")
61
+ super(EditorMain, self).__init__()
62
+
63
+ # 初始化變數
64
+ # Initialize variables
65
+ self.file_menu = None
66
+ self.code_result = None
67
+ self.code_edit = None
68
+ self.menu = None
69
+ self.encoding_menu = None
70
+ self.font_size_menu = None
71
+ self.font_menu = None
72
+ self.working_dir = None
73
+ self.show_system_tray_ray = show_system_tray_ray
74
+
75
+ # 讀取使用者設定
76
+ # Read user settings
77
+ read_user_setting()
78
+
79
+ # 設定語言 (多語系支援)
80
+ # Set language (multi-language support)
81
+ language_wrapper.reset_language(user_setting_dict.get("language", "English"))
82
+
83
+ # Jedi 設定:關閉快取解析器,避免執行緒問題
84
+ # Jedi settings: disable fast parser for thread safety
85
+ jedi.settings.fast_parser = False
86
+ jedi.settings.case_insensitive_completion = False # 關閉大小寫不敏感補全 / Disable case-insensitive completion
87
+
88
+ # Python 編譯器 (可由使用者指定)
89
+ # Python compiler (can be set by user)
90
+ self.python_compiler = None
91
+
92
+ # 除錯模式
93
+ # Debug mode
94
+ self.debug_mode: bool = debug_mode
95
+
96
+ # Windows 系統專用:設定應用程式 ID
97
+ # Windows only: set application ID
98
+ self.id = language_wrapper.language_word_dict.get("application_name")
99
+ if sys.platform in ["win32", "cygwin", "msys"]:
100
+ from ctypes import windll
101
+ windll.shell32.SetCurrentProcessExplicitAppUserModelID(self.id)
102
+
103
+ # 設定 Python 輸出不緩衝
104
+ # Set Python output unbuffered
105
+ os.environ["PYTHONUNBUFFERED"] = "1"
106
+
107
+ # 自動儲存執行緒
108
+ # Auto-save thread
109
+ self.auto_save_thread = None
110
+
111
+ # 預設編碼
112
+ # Default encoding
113
+ self.encoding = "utf-8"
114
+
115
+ # 讀取使用者顏色設定
116
+ # Read user color settings
117
+ read_user_color_setting()
118
+
119
+ # 字型資料庫
120
+ # Font database
121
+ self.font_database = QFontDatabase()
122
+
123
+ # 建立 TabWidget (多分頁編輯器)
124
+ # Create TabWidget (multi-tab editor)
125
+ self.tab_widget = QTabWidget()
126
+ self.tab_widget.setTabsClosable(True) # 可關閉分頁 / Tabs closable
127
+ self.tab_widget.setAttribute(Qt.WidgetAttribute.WA_AlwaysShowToolTips, on=False)
128
+ self.tab_widget.tabCloseRequested.connect(self.close_tab)
129
+
130
+ # 建立計時器,用來處理訊息重導 (stdout/stderr)
131
+ # Timer for redirecting messages (stdout/stderr)
132
+ self.redirect_timer = QTimer(self)
133
+ self.redirect_timer.setInterval(10)
134
+ self.redirect_timer.start()
135
+
136
+ # 設定視窗標題與提示
137
+ # Set window title and tooltip
138
+ self.setWindowTitle(language_wrapper.language_word_dict.get("application_name"))
139
+ self.setToolTip(language_wrapper.language_word_dict.get("application_name"))
140
+
141
+ # 設定選單列
142
+ # Set menu bar
143
+ set_menu_bar(self)
144
+
145
+ # 設定應用程式圖示
146
+ # Set application icon
147
+ self.icon_path = Path(os.getcwd() + "/je_driver_icon.ico")
148
+ self.icon = QIcon(str(self.icon_path))
149
+ if self.icon.isNull() is False:
150
+ self.setWindowIcon(self.icon)
151
+ # 如果系統支援系統匣,則顯示圖示
152
+ # Show system tray icon if available
153
+ if ExtendSystemTray.isSystemTrayAvailable() and self.show_system_tray_ray:
154
+ self.system_tray = ExtendSystemTray(main_window=self)
155
+ self.system_tray.setIcon(self.icon)
156
+ self.system_tray.setVisible(True)
157
+ self.system_tray.show()
158
+ self.system_tray.setToolTip(language_wrapper.language_word_dict.get("application_name"))
159
+
160
+ # 設定輸出重導 (stdout/stderr)
161
+ # Setup output redirection (stdout/stderr)
162
+ redirect_manager_instance.restore_std()
163
+ redirect_manager_instance.set_redirect()
164
+
165
+ # 再次設定計時器,定期檢查輸出
166
+ # Setup timer again to check redirected output
167
+ self.redirect_timer = QTimer(self)
168
+ self.redirect_timer.setInterval(10)
169
+ self.redirect_timer.timeout.connect(self.redirect)
170
+ self.redirect_timer.start()
171
+
172
+ # 建立主要分頁:編輯器與瀏覽器
173
+ # Create main tabs: editor and browser
174
+ main_browser_widget = MainBrowserWidget()
175
+ self.tab_widget.addTab(EditorWidget(self), language_wrapper.language_word_dict.get("tab_name_editor"))
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
185
+ for widget_name, widget in EDITOR_EXTEND_TAB.items():
186
+ self.tab_widget.addTab(widget(), widget_name)
187
+
188
+ # 設定中央元件為 TabWidget
189
+ # Set central widget as TabWidget
190
+ self.setCentralWidget(self.tab_widget)
191
+
192
+ # 啟動時讀取設定
193
+ # Load startup settings
194
+ self.startup_setting()
195
+
196
+ # 如果是 debug 模式,10 秒後自動關閉
197
+ # If debug mode, auto-close after 10 seconds
198
+ if self.debug_mode:
199
+ close_timer = QTimer(self)
200
+ close_timer.setInterval(10000)
201
+ close_timer.timeout.connect(self.debug_close)
202
+ close_timer.start()
203
+
204
+ def clear_code_result(self):
205
+ """
206
+ 清除目前編輯器的輸出結果
207
+ Clear the current editor's output result
208
+ """
209
+ jeditor_logger.info(f"EditorMain clear_code_result")
210
+ widget = self.tab_widget.currentWidget()
211
+ if isinstance(widget, EditorWidget):
212
+ widget.code_result.clear()
213
+
214
+ def redirect(self) -> None:
215
+ """
216
+ 將 stdout/stderr 的訊息導入到編輯器的輸出區域
217
+ Redirect stdout/stderr messages into the editor's output area
218
+ """
219
+ jeditor_logger.info(f"EditorMain redirect")
220
+ # 遍歷所有分頁 (Tab),尋找 EditorWidget
221
+ # Iterate through all tabs to find EditorWidget
222
+ for code_editor in range(self.tab_widget.count()):
223
+ widget = self.tab_widget.widget(code_editor)
224
+ if isinstance(widget, EditorWidget):
225
+ # stdout 輸出處理
226
+ # Handle stdout messages
227
+ if not redirect_manager_instance.std_out_queue.empty():
228
+ output_message = redirect_manager_instance.std_out_queue.get_nowait()
229
+ output_message = str(output_message).strip()
230
+ if output_message:
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
241
+ if not redirect_manager_instance.std_err_queue.empty():
242
+ error_message = redirect_manager_instance.std_err_queue.get_nowait()
243
+ error_message = str(error_message).strip()
244
+ if error_message:
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
253
+
254
+ def startup_setting(self) -> None:
255
+ """
256
+ 啟動時套用使用者設定 (字型、樣式、上次開啟的檔案)
257
+ Apply user settings on startup (fonts, styles, last opened file)
258
+ """
259
+ jeditor_logger.info(f"EditorMain startup_setting")
260
+ # 設定 UI 字型與大小
261
+ # Set UI font and size
262
+ self.setStyleSheet(
263
+ f"font-size: {user_setting_dict.get('ui_font_size', 12)}pt;"
264
+ f"font-family: {user_setting_dict.get('ui_font', 'Lato')};"
265
+ )
266
+
267
+ # 套用到每個編輯器分頁
268
+ # Apply settings to each editor tab
269
+ for code_editor_count in range(self.tab_widget.count()):
270
+ widget = self.tab_widget.widget(code_editor_count)
271
+ if isinstance(widget, EditorWidget):
272
+ # 編輯區字型
273
+ # Font for code editor
274
+ widget.code_edit.setStyleSheet(
275
+ f"font-size: {user_setting_dict.get('font_size', 12)}pt;"
276
+ f"font-family: {user_setting_dict.get('font', 'Lato')};"
277
+ )
278
+ # 輸出區字型
279
+ # Font for output area
280
+ widget.code_result.setStyleSheet(
281
+ f"font-size: {user_setting_dict.get('font_size', 12)}pt;"
282
+ f"font-family: {user_setting_dict.get('font', 'Lato')};"
283
+ )
284
+ # 預設 Python 編譯器
285
+ # Default Python compiler
286
+ self.python_compiler = user_setting_dict.get("python_compiler", None)
287
+
288
+ # 嘗試開啟上次編輯的檔案
289
+ # Try to open last edited file
290
+ last_file = user_setting_dict.get("last_file", None)
291
+ if last_file is not None:
292
+ last_file_path = pathlib.Path(last_file)
293
+ if last_file_path.is_file() and last_file_path.exists() and widget.code_save_thread is None:
294
+ init_new_auto_save_thread(str(last_file_path), widget)
295
+ widget.code_edit.setPlainText(read_file(widget.current_file)[1])
296
+ widget.code_edit.current_file = widget.current_file
297
+ widget.code_edit.reset_highlighter()
298
+ file_is_open_manager_dict.update({str(last_file_path): str(last_file_path.name)})
299
+ widget.rename_self_tab()
300
+
301
+ # 套用 UI 樣式 (主題)
302
+ # Apply UI stylesheet (theme)
303
+ self.apply_stylesheet(self, user_setting_dict.get("ui_style", "dark_amber.xml"))
304
+ # 更新顏色設定
305
+ # Update color settings
306
+ update_actually_color_dict()
307
+
308
+ def go_to_new_tab(self, file_path: Path):
309
+ """
310
+ 開啟新分頁並載入檔案
311
+ Open a new tab and load a file
312
+ """
313
+ jeditor_logger.info(f"EditorMain go_to_new_tab file_path: {file_path}")
314
+ if file_is_open_manager_dict.get(str(file_path), None) is None:
315
+ # 建立新的編輯器分頁
316
+ # Create a new editor tab
317
+ editor_widget = EditorWidget(self)
318
+ self.tab_widget.addTab(
319
+ editor_widget,
320
+ f"{language_wrapper.language_word_dict.get('tab_menu_editor_tab_name')} "
321
+ f"{self.tab_widget.count()}"
322
+ )
323
+ self.tab_widget.setCurrentWidget(editor_widget)
324
+ editor_widget.open_an_file(file_path)
325
+ else:
326
+ # 如果檔案已開啟,直接切換到該分頁
327
+ # If file already opened, switch to that tab
328
+ widget: QWidget = self.tab_widget.findChild(EditorWidget, str(file_path))
329
+ self.tab_widget.setCurrentWidget(widget)
330
+
331
+ def closeEvent(self, event) -> None:
332
+ """
333
+ 視窗關閉事件:儲存使用者設定
334
+ Window close event: save user settings
335
+ """
336
+ jeditor_logger.info("EditorMain closeEvent")
337
+ write_user_setting()
338
+ write_user_color_setting()
339
+ super().closeEvent(event)
340
+
341
+ def event(self, event: QEvent) -> bool:
342
+ """
343
+ 事件處理:忽略 ToolTip 類型事件
344
+ Event handler: ignore ToolTip events
345
+ """
346
+ jeditor_logger.info(f"EditorMain event: {event}")
347
+ if event.type() == QEvent.Type.ToolTip:
348
+ event.ignore()
349
+ return False
350
+ else:
351
+ return super().event(event)
352
+
353
+ def close_tab(self, index: int):
354
+ """
355
+ 關閉指定索引的分頁
356
+ Close tab at given index
357
+ """
358
+ widget = self.tab_widget.widget(index)
359
+ if widget:
360
+ widget.close()
361
+ self.tab_widget.removeTab(index)
362
+
363
+ @classmethod
364
+ def debug_close(cls):
365
+ """
366
+ 除錯模式下自動關閉程式
367
+ Auto-close the program in debug mode
368
+ """
369
+ sys.exit(0)
File without changes
@@ -0,0 +1,104 @@
1
+ from __future__ import annotations # 啟用未來版本的型別註解功能 / Enable postponed evaluation of type annotations
2
+
3
+ from typing import TYPE_CHECKING # 僅在型別檢查時使用,避免循環匯入 / Used only for type checking to avoid circular imports
4
+
5
+ from je_editor.pyside_ui.main_ui.editor.editor_widget import EditorWidget # 編輯器分頁元件 / Editor tab widget
6
+ from je_editor.utils.logging.loggin_instance import jeditor_logger # 專案內的日誌紀錄器 / Project logger
7
+ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapper # 多語系支援 / Multi-language wrapper
8
+
9
+ if TYPE_CHECKING:
10
+ from je_editor.pyside_ui.main_ui.main_editor import EditorMain # 僅在型別檢查時匯入 / Import only for type checking
11
+
12
+ from PySide6.QtGui import QAction, QKeySequence # Qt 動作與快捷鍵 / Qt actions and shortcuts
13
+ from yapf.yapflib.yapf_api import FormatCode # YAPF 程式碼格式化工具 / YAPF code formatter
14
+
15
+ from je_editor.utils.json_format.json_process import reformat_json # JSON 格式化工具 / JSON reformatter
16
+
17
+
18
+ def set_check_menu(ui_we_want_to_set: EditorMain) -> None:
19
+ """
20
+ 建立「程式碼檢查/格式化」選單,並加入三個功能:
21
+ - 使用 YAPF 重新格式化 Python 程式碼
22
+ - 重新格式化 JSON
23
+ - 檢查 Python 檔案格式
24
+
25
+ Create "Check/Format Code" menu with three actions:
26
+ - Reformat Python code with YAPF
27
+ - Reformat JSON
28
+ - Check Python file format
29
+ """
30
+ jeditor_logger.info(f"build_check_style_menu.py set_check_menu ui_we_want_to_set: {ui_we_want_to_set}")
31
+
32
+ # 在主選單中新增一個子選單 / Add submenu to main menu
33
+ ui_we_want_to_set.check_menu = ui_we_want_to_set.menu.addMenu(
34
+ language_wrapper.language_word_dict.get("check_code_style_menu_label"))
35
+
36
+ # === 1. Yapf Python 程式碼格式化 / Yapf Python code reformat ===
37
+ ui_we_want_to_set.check_menu.yapf_check_python_action = QAction(
38
+ language_wrapper.language_word_dict.get("yapf_reformat_label"))
39
+ ui_we_want_to_set.check_menu.yapf_check_python_action.setShortcut(
40
+ QKeySequence("Ctrl+Shift+Y")) # 設定快捷鍵 / Set shortcut
41
+ ui_we_want_to_set.check_menu.yapf_check_python_action.triggered.connect(
42
+ lambda: yapf_check_python_code(ui_we_want_to_set)
43
+ )
44
+ ui_we_want_to_set.check_menu.addAction(ui_we_want_to_set.check_menu.yapf_check_python_action)
45
+
46
+ # === 2. JSON 重新格式化 / Reformat JSON ===
47
+ ui_we_want_to_set.check_menu.reformat_json_action = QAction(
48
+ language_wrapper.language_word_dict.get("reformat_json_label"))
49
+ ui_we_want_to_set.check_menu.reformat_json_action.setShortcut("Ctrl+j")
50
+ ui_we_want_to_set.check_menu.reformat_json_action.triggered.connect(
51
+ lambda: reformat_json_text(ui_we_want_to_set)
52
+ )
53
+ ui_we_want_to_set.check_menu.addAction(ui_we_want_to_set.check_menu.reformat_json_action)
54
+
55
+ # === 3. Python 格式檢查 / Python format check ===
56
+ ui_we_want_to_set.check_menu.check_python_format = QAction(
57
+ language_wrapper.language_word_dict.get("python_format_checker"))
58
+ ui_we_want_to_set.check_menu.check_python_format.setShortcut("Ctrl+Alt+p")
59
+ ui_we_want_to_set.check_menu.check_python_format.triggered.connect(
60
+ lambda: check_python_format(ui_we_want_to_set)
61
+ )
62
+ ui_we_want_to_set.check_menu.addAction(ui_we_want_to_set.check_menu.check_python_format)
63
+
64
+
65
+ def yapf_check_python_code(ui_we_want_to_set: EditorMain) -> None:
66
+ """
67
+ 使用 YAPF 重新格式化目前分頁中的 Python 程式碼
68
+ Reformat current tab's Python code using YAPF
69
+ """
70
+ jeditor_logger.info(f"build_check_style_menu.py yapf_check_python_code ui_we_want_to_set: {ui_we_want_to_set}")
71
+ widget = ui_we_want_to_set.tab_widget.currentWidget()
72
+ if isinstance(widget, EditorWidget):
73
+ code_text = widget.code_edit.toPlainText() # 取得編輯器文字 / Get code text
74
+ widget.code_result.setPlainText("") # 清空結果區域 / Clear result area
75
+ format_code = FormatCode(
76
+ unformatted_source=code_text,
77
+ style_config="google" # 使用 Google 風格 / Use Google style
78
+ )
79
+ if isinstance(format_code, tuple):
80
+ widget.code_edit.setPlainText(format_code[0]) # 將格式化後的程式碼寫回編輯器 / Write formatted code back
81
+
82
+
83
+ def reformat_json_text(ui_we_want_to_set: EditorMain) -> None:
84
+ """
85
+ 重新格式化目前分頁中的 JSON 文字
86
+ Reformat JSON text in the current editor tab
87
+ """
88
+ jeditor_logger.info(f"build_check_style_menu.py reformat_json_text ui_we_want_to_set: {ui_we_want_to_set}")
89
+ widget = ui_we_want_to_set.tab_widget.currentWidget()
90
+ if isinstance(widget, EditorWidget):
91
+ code_text = widget.code_edit.toPlainText()
92
+ widget.code_result.setPlainText("")
93
+ widget.code_edit.setPlainText(reformat_json(code_text)) # 呼叫 JSON 格式化工具 / Call JSON reformatter
94
+
95
+
96
+ def check_python_format(ui_we_want_to_set: EditorMain) -> None:
97
+ """
98
+ 呼叫 EditorWidget 的檔案格式檢查功能
99
+ Call EditorWidget's file format checker
100
+ """
101
+ jeditor_logger.info(f"build_check_style_menu.py check_python_format ui_we_want_to_set: {ui_we_want_to_set}")
102
+ widget = ui_we_want_to_set.tab_widget.currentWidget()
103
+ if isinstance(widget, EditorWidget):
104
+ widget.check_file_format()
File without changes