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.
- je_editor/__init__.py +26 -21
- je_editor/__main__.py +1 -1
- je_editor/code_scan/ruff_thread.py +58 -0
- je_editor/code_scan/watchdog_implement.py +56 -0
- je_editor/code_scan/watchdog_thread.py +78 -0
- je_editor/git_client/commit_graph.py +77 -0
- je_editor/git_client/git_action.py +175 -0
- je_editor/git_client/git_cli.py +66 -0
- je_editor/pyside_ui/browser/browser_download_window.py +75 -0
- je_editor/pyside_ui/browser/browser_serach_lineedit.py +51 -0
- je_editor/pyside_ui/browser/browser_view.py +87 -0
- je_editor/pyside_ui/browser/browser_widget.py +103 -0
- je_editor/pyside_ui/browser/main_browser_widget.py +85 -0
- je_editor/pyside_ui/code/auto_save/auto_save_manager.py +60 -0
- je_editor/pyside_ui/code/auto_save/auto_save_thread.py +59 -0
- je_editor/pyside_ui/code/code_format/pep8_format.py +130 -0
- je_editor/pyside_ui/code/code_process/code_exec.py +267 -0
- je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +412 -0
- je_editor/pyside_ui/code/running_process_manager.py +48 -0
- je_editor/pyside_ui/code/shell_process/shell_exec.py +236 -0
- je_editor/pyside_ui/code/syntax/python_syntax.py +99 -0
- je_editor/pyside_ui/code/syntax/syntax_setting.py +95 -0
- je_editor/pyside_ui/code/textedit_code_result/code_record.py +75 -0
- je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +172 -0
- je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +71 -0
- je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +68 -0
- je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +111 -0
- je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +67 -0
- je_editor/pyside_ui/dialog/search_ui/search_error_box.py +49 -0
- je_editor/pyside_ui/dialog/search_ui/search_text_box.py +49 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +90 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/line_number_code_viewer.py +141 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/multi_file_diff_viewer.py +88 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/side_by_side_diff_widget.py +284 -0
- je_editor/pyside_ui/git_ui/git_client/commit_table.py +65 -0
- je_editor/pyside_ui/git_ui/git_client/git_branch_tree_widget.py +156 -0
- je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +799 -0
- je_editor/pyside_ui/git_ui/git_client/graph_view.py +218 -0
- je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +34 -0
- je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +36 -0
- je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +147 -0
- je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +84 -0
- je_editor/pyside_ui/main_ui/console_widget/console_gui.py +162 -0
- je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +84 -0
- je_editor/pyside_ui/main_ui/dock/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/dock/destroy_dock.py +50 -0
- je_editor/pyside_ui/main_ui/editor/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/editor/editor_widget.py +301 -0
- je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +70 -0
- je_editor/pyside_ui/main_ui/editor/process_input.py +101 -0
- je_editor/pyside_ui/main_ui/ipython_widget/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +78 -0
- je_editor/pyside_ui/main_ui/main_editor.py +369 -0
- je_editor/pyside_ui/main_ui/menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/check_style_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +104 -0
- je_editor/pyside_ui/main_ui/menu/dock_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +208 -0
- je_editor/pyside_ui/main_ui/menu/file_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +186 -0
- je_editor/pyside_ui/main_ui/menu/help_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +100 -0
- je_editor/pyside_ui/main_ui/menu/language_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +89 -0
- je_editor/pyside_ui/main_ui/menu/python_env_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +238 -0
- je_editor/pyside_ui/main_ui/menu/run_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +160 -0
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +109 -0
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +101 -0
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +98 -0
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +41 -0
- je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +63 -0
- je_editor/pyside_ui/main_ui/menu/style_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +73 -0
- je_editor/pyside_ui/main_ui/menu/tab_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +275 -0
- je_editor/pyside_ui/main_ui/menu/text_menu/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +135 -0
- je_editor/pyside_ui/main_ui/save_settings/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +33 -0
- je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +103 -0
- je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +58 -0
- je_editor/pyside_ui/main_ui/system_tray/__init__.py +0 -0
- je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +90 -0
- je_editor/start_editor.py +32 -8
- je_editor/utils/encodings/python_encodings.py +100 -97
- je_editor/utils/exception/exception_tags.py +11 -11
- je_editor/utils/file/open/open_file.py +38 -22
- je_editor/utils/file/save/save_file.py +40 -16
- je_editor/utils/json/json_file.py +36 -15
- je_editor/utils/json_format/json_process.py +38 -2
- je_editor/utils/logging/__init__.py +0 -0
- je_editor/utils/logging/loggin_instance.py +57 -0
- je_editor/utils/multi_language/__init__.py +0 -0
- je_editor/utils/multi_language/english.py +221 -0
- je_editor/utils/multi_language/multi_language_wrapper.py +54 -0
- je_editor/utils/multi_language/traditional_chinese.py +214 -0
- je_editor/utils/redirect_manager/redirect_manager_class.py +67 -25
- je_editor/utils/venv_check/__init__.py +0 -0
- je_editor/utils/venv_check/check_venv.py +51 -0
- je_editor-0.0.228.dist-info/METADATA +99 -0
- je_editor-0.0.228.dist-info/RECORD +140 -0
- {je_editor-0.0.104.dist-info → je_editor-0.0.228.dist-info}/WHEEL +1 -1
- {je_editor-0.0.104.dist-info → je_editor-0.0.228.dist-info/licenses}/LICENSE +1 -1
- je_editor/pyside_ui/auto_save/auto_save_thread.py +0 -34
- je_editor/pyside_ui/code_editor/code_edit_plaintext.py +0 -143
- je_editor/pyside_ui/code_process/code_exec.py +0 -190
- je_editor/pyside_ui/code_result/code_record.py +0 -39
- je_editor/pyside_ui/colors/global_color.py +0 -4
- je_editor/pyside_ui/file_dialog/open_file_dialog.py +0 -27
- je_editor/pyside_ui/file_dialog/save_file_dialog.py +0 -24
- je_editor/pyside_ui/main_ui/editor_main_ui/main_editor.py +0 -183
- je_editor/pyside_ui/main_ui_setting/ui_setting.py +0 -36
- je_editor/pyside_ui/menu/menu_bar/check_style_menu/build_check_style_menu.py +0 -44
- je_editor/pyside_ui/menu/menu_bar/file_menu/build_file_menu.py +0 -30
- je_editor/pyside_ui/menu/menu_bar/help_menu/build_help_menu.py +0 -39
- je_editor/pyside_ui/menu/menu_bar/run_menu/build_run_menu.py +0 -102
- je_editor/pyside_ui/menu/menu_bar/set_menu_bar.py +0 -24
- je_editor/pyside_ui/menu/menu_bar/venv_menu/build_venv_menu.py +0 -74
- je_editor/pyside_ui/search_ui/search_error_box.py +0 -20
- je_editor/pyside_ui/search_ui/search_text_box.py +0 -20
- je_editor/pyside_ui/shell_process/shell_exec.py +0 -157
- je_editor/pyside_ui/syntax/python_syntax.py +0 -99
- je_editor/pyside_ui/treeview/project_treeview/set_project_treeview.py +0 -47
- je_editor/pyside_ui/user_setting/user_setting_file.py +0 -23
- je_editor-0.0.104.dist-info/METADATA +0 -84
- je_editor-0.0.104.dist-info/RECORD +0 -69
- /je_editor/{pyside_ui/auto_save → code_scan}/__init__.py +0 -0
- /je_editor/{pyside_ui/code_editor → git_client}/__init__.py +0 -0
- /je_editor/pyside_ui/{code_process → browser}/__init__.py +0 -0
- /je_editor/pyside_ui/{code_result → code}/__init__.py +0 -0
- /je_editor/pyside_ui/{colors → code/auto_save}/__init__.py +0 -0
- /je_editor/pyside_ui/{file_dialog → code/code_format}/__init__.py +0 -0
- /je_editor/pyside_ui/{main_ui/editor_main_ui → code/code_process}/__init__.py +0 -0
- /je_editor/pyside_ui/{main_ui_setting → code/plaintext_code_edit}/__init__.py +0 -0
- /je_editor/pyside_ui/{menu → code/shell_process}/__init__.py +0 -0
- /je_editor/pyside_ui/{menu/menu_bar → code/syntax}/__init__.py +0 -0
- /je_editor/pyside_ui/{menu/menu_bar/check_style_menu → code/textedit_code_result}/__init__.py +0 -0
- /je_editor/pyside_ui/{menu/menu_bar/file_menu → code/variable_inspector}/__init__.py +0 -0
- /je_editor/pyside_ui/{menu/menu_bar/help_menu → dialog}/__init__.py +0 -0
- /je_editor/pyside_ui/{menu/menu_bar/run_menu → dialog/ai_dialog}/__init__.py +0 -0
- /je_editor/pyside_ui/{menu/menu_bar/venv_menu → dialog/file_dialog}/__init__.py +0 -0
- /je_editor/pyside_ui/{search_ui → dialog/search_ui}/__init__.py +0 -0
- /je_editor/pyside_ui/{shell_process → git_ui}/__init__.py +0 -0
- /je_editor/pyside_ui/{syntax → git_ui/code_diff_compare}/__init__.py +0 -0
- /je_editor/pyside_ui/{treeview → git_ui/git_client}/__init__.py +0 -0
- /je_editor/pyside_ui/{treeview/project_treeview → main_ui/ai_widget}/__init__.py +0 -0
- /je_editor/pyside_ui/{user_setting → main_ui/console_widget}/__init__.py +0 -0
- {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
|
|
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
|