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.
- je_editor/git_client/commit_graph.py +7 -7
- je_editor/git_client/git_action.py +0 -7
- je_editor/pyside_ui/browser/browser_widget.py +24 -11
- je_editor/pyside_ui/browser/main_browser_widget.py +40 -27
- je_editor/pyside_ui/code/auto_save/auto_save_manager.py +34 -2
- je_editor/pyside_ui/code/auto_save/auto_save_thread.py +19 -6
- je_editor/pyside_ui/code/code_format/pep8_format.py +53 -9
- je_editor/pyside_ui/code/code_process/code_exec.py +88 -52
- je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +116 -55
- je_editor/pyside_ui/code/running_process_manager.py +19 -1
- je_editor/pyside_ui/code/shell_process/shell_exec.py +71 -48
- je_editor/pyside_ui/code/syntax/python_syntax.py +45 -10
- je_editor/pyside_ui/code/syntax/syntax_setting.py +40 -12
- je_editor/pyside_ui/code/textedit_code_result/code_record.py +34 -12
- je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +53 -6
- je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +30 -3
- je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +35 -2
- je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +33 -5
- je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +25 -3
- je_editor/pyside_ui/dialog/search_ui/search_error_box.py +26 -1
- je_editor/pyside_ui/dialog/search_ui/search_text_box.py +26 -1
- je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +11 -11
- je_editor/pyside_ui/git_ui/git_client/commit_table.py +46 -8
- je_editor/pyside_ui/git_ui/git_client/git_branch_tree_widget.py +49 -15
- je_editor/pyside_ui/git_ui/git_client/graph_view.py +64 -20
- je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +20 -5
- je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +20 -1
- je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +56 -41
- je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +45 -6
- je_editor/pyside_ui/main_ui/console_widget/console_gui.py +44 -12
- je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +34 -13
- je_editor/pyside_ui/main_ui/dock/destroy_dock.py +33 -2
- je_editor/pyside_ui/main_ui/editor/editor_widget.py +104 -20
- je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +34 -7
- je_editor/pyside_ui/main_ui/editor/process_input.py +38 -11
- je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +46 -11
- je_editor/pyside_ui/main_ui/main_editor.py +175 -37
- je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +51 -28
- je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +80 -22
- je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +70 -17
- je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +34 -3
- je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +41 -1
- je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +100 -42
- je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +57 -7
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +50 -4
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +52 -6
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +44 -4
- je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +23 -1
- je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +37 -12
- je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +44 -7
- je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +126 -28
- je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +65 -1
- je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +18 -1
- je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +33 -3
- je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +38 -11
- je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +39 -2
- je_editor/start_editor.py +26 -1
- je_editor/utils/encodings/python_encodings.py +101 -98
- je_editor/utils/file/open/open_file.py +36 -19
- je_editor/utils/file/save/save_file.py +35 -14
- je_editor/utils/json/json_file.py +29 -14
- je_editor/utils/json_format/json_process.py +33 -2
- je_editor/utils/logging/loggin_instance.py +38 -8
- je_editor/utils/multi_language/multi_language_wrapper.py +29 -4
- je_editor/utils/redirect_manager/redirect_manager_class.py +49 -11
- je_editor/utils/venv_check/check_venv.py +45 -15
- {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/METADATA +1 -1
- {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/RECORD +71 -71
- {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/WHEEL +0 -0
- {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/licenses/LICENSE +0 -0
- {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/top_level.txt +0 -0
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
|
+
# 啟用未來註解功能,允許型別提示使用字串前向參照
|
|
3
|
+
# Enable future annotations, allowing forward references in type hints
|
|
2
4
|
|
|
3
5
|
from typing import TYPE_CHECKING
|
|
4
|
-
|
|
5
6
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
6
7
|
|
|
7
8
|
if TYPE_CHECKING:
|
|
8
9
|
from je_editor.pyside_ui.main_ui.main_editor import EditorMain
|
|
10
|
+
# 僅在型別檢查時匯入 EditorMain,避免循環依賴
|
|
11
|
+
# Import EditorMain only for type checking
|
|
12
|
+
|
|
9
13
|
import sys
|
|
10
14
|
|
|
11
15
|
from PySide6.QtGui import QAction
|
|
@@ -14,38 +18,71 @@ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapp
|
|
|
14
18
|
|
|
15
19
|
|
|
16
20
|
class ExtendSystemTray(QSystemTrayIcon):
|
|
21
|
+
"""
|
|
22
|
+
擴充系統匣功能,提供隱藏、最大化、還原、關閉等操作
|
|
23
|
+
Extend system tray functionality with hide, maximize, restore, and close actions
|
|
24
|
+
"""
|
|
17
25
|
|
|
18
26
|
def __init__(self, main_window: EditorMain):
|
|
27
|
+
# 初始化並記錄日誌
|
|
28
|
+
# Initialize and log
|
|
19
29
|
jeditor_logger.info(f"Init ExtendSystemTray main_window: {main_window}")
|
|
20
30
|
super().__init__(parent=main_window)
|
|
31
|
+
|
|
32
|
+
# 建立右鍵選單
|
|
33
|
+
# Create context menu
|
|
21
34
|
self.menu = QMenu()
|
|
22
35
|
self.main_window = main_window
|
|
36
|
+
|
|
37
|
+
# === 隱藏主視窗 / Hide main window ===
|
|
23
38
|
self.hide_main_window_action = QAction(
|
|
24
39
|
language_wrapper.language_word_dict.get("system_tray_hide"))
|
|
25
40
|
self.hide_main_window_action.triggered.connect(self.main_window.hide)
|
|
26
41
|
self.menu.addAction(self.hide_main_window_action)
|
|
42
|
+
|
|
43
|
+
# === 最大化主視窗 / Maximize main window ===
|
|
27
44
|
self.maximized_main_window_action = QAction(
|
|
28
45
|
language_wrapper.language_word_dict.get("system_tray_maximized"))
|
|
29
46
|
self.maximized_main_window_action.triggered.connect(self.main_window.showMaximized)
|
|
30
47
|
self.menu.addAction(self.maximized_main_window_action)
|
|
48
|
+
|
|
49
|
+
# === 還原主視窗 / Restore main window ===
|
|
31
50
|
self.normal_main_window_action = QAction(
|
|
32
51
|
language_wrapper.language_word_dict.get("system_tray_normal"))
|
|
33
52
|
self.normal_main_window_action.triggered.connect(self.main_window.showNormal)
|
|
34
53
|
self.menu.addAction(self.normal_main_window_action)
|
|
54
|
+
|
|
55
|
+
# === 關閉應用程式 / Close application ===
|
|
35
56
|
self.close_main_window_action = QAction(
|
|
36
57
|
language_wrapper.language_word_dict.get("system_tray_close"))
|
|
37
58
|
self.close_main_window_action.triggered.connect(self.close_all)
|
|
38
59
|
self.menu.addAction(self.close_main_window_action)
|
|
60
|
+
|
|
61
|
+
# 設定選單到系統匣圖示
|
|
62
|
+
# Attach menu to system tray icon
|
|
39
63
|
self.setContextMenu(self.menu)
|
|
64
|
+
|
|
65
|
+
# 綁定點擊事件 (例如雙擊)
|
|
66
|
+
# Connect click events (e.g., double-click)
|
|
40
67
|
self.activated.connect(self.clicked)
|
|
41
68
|
|
|
42
69
|
def close_all(self):
|
|
70
|
+
"""
|
|
71
|
+
關閉應用程式:隱藏圖示、關閉主視窗並結束程式
|
|
72
|
+
Close the application: hide tray icon, close main window, and exit program
|
|
73
|
+
"""
|
|
43
74
|
jeditor_logger.info("ExtendSystemTray close_all")
|
|
44
75
|
self.setVisible(False)
|
|
45
76
|
self.main_window.close()
|
|
46
77
|
sys.exit(0)
|
|
47
78
|
|
|
48
79
|
def clicked(self, reason):
|
|
80
|
+
"""
|
|
81
|
+
處理系統匣點擊事件
|
|
82
|
+
Handle system tray click events
|
|
83
|
+
"""
|
|
49
84
|
if reason == self.ActivationReason.DoubleClick:
|
|
85
|
+
# 如果是雙擊,最大化主視窗
|
|
86
|
+
# If double-click, maximize the main window
|
|
50
87
|
jeditor_logger.info("ExtendSystemTray DoubleClick")
|
|
51
|
-
self.main_window.showMaximized()
|
|
88
|
+
self.main_window.showMaximized()
|
je_editor/start_editor.py
CHANGED
|
@@ -8,10 +8,35 @@ from je_editor.pyside_ui.main_ui.main_editor import EditorMain
|
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
def start_editor(debug_mode: bool = False) -> None:
|
|
11
|
+
"""
|
|
12
|
+
功能說明 (Function Description):
|
|
13
|
+
啟動編輯器主程式,建立 QApplication 實例,套用主題,並顯示主視窗。
|
|
14
|
+
Start the main editor application, create QApplication instance, apply theme, and show main window.
|
|
15
|
+
|
|
16
|
+
:param debug_mode: 是否啟用除錯模式 / whether to enable debug mode
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
# 嘗試取得現有的 QCoreApplication 實例
|
|
20
|
+
# Try to get an existing QCoreApplication instance
|
|
11
21
|
new_editor = QCoreApplication.instance()
|
|
22
|
+
|
|
23
|
+
# 如果沒有現有實例,建立新的 QApplication
|
|
24
|
+
# If no instance exists, create a new QApplication
|
|
12
25
|
if new_editor is None:
|
|
13
26
|
new_editor = QApplication(sys.argv)
|
|
27
|
+
|
|
28
|
+
# 建立主視窗,傳入 debug_mode
|
|
29
|
+
# Create the main editor window, passing debug_mode
|
|
14
30
|
window = EditorMain(debug_mode)
|
|
31
|
+
|
|
32
|
+
# 套用 qt-material 主題 (dark amber)
|
|
33
|
+
# Apply qt-material theme (dark amber)
|
|
15
34
|
apply_stylesheet(new_editor, theme='dark_amber.xml')
|
|
35
|
+
|
|
36
|
+
# 最大化顯示主視窗
|
|
37
|
+
# Show the main window maximized
|
|
16
38
|
window.showMaximized()
|
|
17
|
-
|
|
39
|
+
|
|
40
|
+
# 啟動事件迴圈,並在結束時退出程式
|
|
41
|
+
# Start the event loop and exit the program when it ends
|
|
42
|
+
sys.exit(new_editor.exec())
|
|
@@ -1,99 +1,102 @@
|
|
|
1
|
+
# 定義一個 Python 支援的文字編碼清單
|
|
2
|
+
# Define a list of text encodings supported by Python
|
|
3
|
+
|
|
1
4
|
python_encodings_list = [
|
|
2
|
-
'ascii',
|
|
3
|
-
'big5',
|
|
4
|
-
'big5hkscs',
|
|
5
|
-
'cp037',
|
|
6
|
-
'cp273',
|
|
7
|
-
'cp424',
|
|
8
|
-
'cp437',
|
|
9
|
-
'cp500',
|
|
10
|
-
'cp720',
|
|
11
|
-
'cp737',
|
|
12
|
-
'cp775',
|
|
13
|
-
'cp850',
|
|
14
|
-
'cp852',
|
|
15
|
-
'cp855',
|
|
16
|
-
'cp856',
|
|
17
|
-
'cp857',
|
|
18
|
-
'cp858',
|
|
19
|
-
'cp860',
|
|
20
|
-
'cp861',
|
|
21
|
-
'cp862',
|
|
22
|
-
'cp863',
|
|
23
|
-
'cp864',
|
|
24
|
-
'cp865',
|
|
25
|
-
'cp866',
|
|
26
|
-
'cp869',
|
|
27
|
-
'cp874',
|
|
28
|
-
'cp875',
|
|
29
|
-
'cp932',
|
|
30
|
-
'cp949',
|
|
31
|
-
'cp950',
|
|
32
|
-
'cp1006',
|
|
33
|
-
'cp1026',
|
|
34
|
-
'cp1125',
|
|
35
|
-
'cp1140',
|
|
36
|
-
'cp1250',
|
|
37
|
-
'cp1251',
|
|
38
|
-
'cp1252',
|
|
39
|
-
'cp1253',
|
|
40
|
-
'cp1254',
|
|
41
|
-
'cp1255',
|
|
42
|
-
'cp1256',
|
|
43
|
-
'cp1257',
|
|
44
|
-
'cp1258',
|
|
45
|
-
'euc_jp',
|
|
46
|
-
'euc_jis_2004',
|
|
47
|
-
'euc_jisx0213',
|
|
48
|
-
'euc_kr',
|
|
49
|
-
'gb2312',
|
|
50
|
-
'gbk',
|
|
51
|
-
'gb18030',
|
|
52
|
-
'hz',
|
|
53
|
-
'iso2022_jp',
|
|
54
|
-
'iso2022_jp_1',
|
|
55
|
-
'iso2022_jp_2',
|
|
56
|
-
'iso2022_jp_2004',
|
|
57
|
-
'iso2022_jp_3',
|
|
58
|
-
'iso2022_jp_ext',
|
|
59
|
-
'iso2022_kr',
|
|
60
|
-
'latin_1',
|
|
61
|
-
'iso8859_2',
|
|
62
|
-
'iso8859_3',
|
|
63
|
-
'iso8859_4',
|
|
64
|
-
'iso8859_5',
|
|
65
|
-
'iso8859_6',
|
|
66
|
-
'iso8859_7',
|
|
67
|
-
'iso8859_8',
|
|
68
|
-
'iso8859_9',
|
|
69
|
-
'iso8859_10',
|
|
70
|
-
'iso8859_11',
|
|
71
|
-
'iso8859_13',
|
|
72
|
-
'iso8859_14',
|
|
73
|
-
'iso8859_15',
|
|
74
|
-
'iso8859_16',
|
|
75
|
-
'johab',
|
|
76
|
-
'koi8_r',
|
|
77
|
-
'koi8_t',
|
|
78
|
-
'koi8_u',
|
|
79
|
-
'kz1048',
|
|
80
|
-
'mac_cyrillic',
|
|
81
|
-
'mac_greek',
|
|
82
|
-
'mac_iceland',
|
|
83
|
-
'mac_latin2',
|
|
84
|
-
'mac_roman',
|
|
85
|
-
'mac_turkish',
|
|
86
|
-
'ptcp154',
|
|
87
|
-
'shift_jis',
|
|
88
|
-
'shift_jis_2004',
|
|
89
|
-
'shift_jisx0213',
|
|
90
|
-
'utf_32',
|
|
91
|
-
'utf_32_be',
|
|
92
|
-
'utf_32_le',
|
|
93
|
-
'utf_16',
|
|
94
|
-
'utf_16_be',
|
|
95
|
-
'utf_16_le',
|
|
96
|
-
'utf_7',
|
|
97
|
-
'utf_8',
|
|
98
|
-
'utf_8_sig'
|
|
99
|
-
]
|
|
5
|
+
'ascii', # ASCII 編碼 (基本的英文字符集, 7-bit) / Basic English character set
|
|
6
|
+
'big5', # Big5 編碼 (繁體中文常用, 台灣/香港) / Traditional Chinese encoding (Taiwan/HK)
|
|
7
|
+
'big5hkscs', # Big5-HKSCS (香港增補字集) / Big5 with Hong Kong Supplementary Character Set
|
|
8
|
+
'cp037', # IBM EBCDIC US/Canada / IBM mainframe encoding
|
|
9
|
+
'cp273', # IBM EBCDIC Germany / 德國 EBCDIC 編碼
|
|
10
|
+
'cp424', # IBM EBCDIC Hebrew / 希伯來文編碼
|
|
11
|
+
'cp437', # 原始 IBM PC 編碼 (DOS Latin US) / Original IBM PC encoding
|
|
12
|
+
'cp500', # IBM EBCDIC International / 國際版 EBCDIC
|
|
13
|
+
'cp720', # 阿拉伯文 (DOS) / Arabic (DOS)
|
|
14
|
+
'cp737', # 希臘文 (DOS) / Greek (DOS)
|
|
15
|
+
'cp775', # 波羅的海語系 (DOS) / Baltic languages (DOS)
|
|
16
|
+
'cp850', # 西歐語系 (DOS) / Western Europe (DOS)
|
|
17
|
+
'cp852', # 中歐語系 (DOS) / Central Europe (DOS)
|
|
18
|
+
'cp855', # 西里爾字母 (DOS) / Cyrillic (DOS)
|
|
19
|
+
'cp856', # 希伯來文 (DOS) / Hebrew (DOS)
|
|
20
|
+
'cp857', # 土耳其文 (DOS) / Turkish (DOS)
|
|
21
|
+
'cp858', # 西歐語系 (含歐元符號) / Western Europe with Euro sign
|
|
22
|
+
'cp860', # 葡萄牙文 (DOS) / Portuguese (DOS)
|
|
23
|
+
'cp861', # 冰島文 (DOS) / Icelandic (DOS)
|
|
24
|
+
'cp862', # 希伯來文 (DOS) / Hebrew (DOS)
|
|
25
|
+
'cp863', # 加拿大法文 (DOS) / Canadian French (DOS)
|
|
26
|
+
'cp864', # 阿拉伯文 (DOS) / Arabic (DOS)
|
|
27
|
+
'cp865', # 北歐語系 (DOS) / Nordic languages (DOS)
|
|
28
|
+
'cp866', # 俄文 (DOS) / Russian (DOS)
|
|
29
|
+
'cp869', # 希臘文 (DOS) / Greek (DOS)
|
|
30
|
+
'cp874', # 泰文 (Windows) / Thai (Windows)
|
|
31
|
+
'cp875', # IBM EBCDIC Greek / 希臘文 EBCDIC
|
|
32
|
+
'cp932', # 日文 Shift_JIS (Windows) / Japanese Shift_JIS (Windows)
|
|
33
|
+
'cp949', # 韓文 (Windows) / Korean (Windows)
|
|
34
|
+
'cp950', # 繁體中文 Big5 (Windows) / Traditional Chinese Big5 (Windows)
|
|
35
|
+
'cp1006', # 烏爾都文 (Urdu) / Urdu
|
|
36
|
+
'cp1026', # IBM EBCDIC Turkish / 土耳其文 EBCDIC
|
|
37
|
+
'cp1125', # 烏克蘭文 (DOS) / Ukrainian (DOS)
|
|
38
|
+
'cp1140', # EBCDIC with Euro / EBCDIC 含歐元符號
|
|
39
|
+
'cp1250', # 中歐語系 (Windows) / Central Europe (Windows)
|
|
40
|
+
'cp1251', # 西里爾字母 (Windows) / Cyrillic (Windows)
|
|
41
|
+
'cp1252', # 西歐語系 (Windows, 常見) / Western Europe (Windows, very common)
|
|
42
|
+
'cp1253', # 希臘文 (Windows) / Greek (Windows)
|
|
43
|
+
'cp1254', # 土耳其文 (Windows) / Turkish (Windows)
|
|
44
|
+
'cp1255', # 希伯來文 (Windows) / Hebrew (Windows)
|
|
45
|
+
'cp1256', # 阿拉伯文 (Windows) / Arabic (Windows)
|
|
46
|
+
'cp1257', # 波羅的海語系 (Windows) / Baltic (Windows)
|
|
47
|
+
'cp1258', # 越南文 (Windows) / Vietnamese (Windows)
|
|
48
|
+
'euc_jp', # 日文 EUC 編碼 / Japanese EUC encoding
|
|
49
|
+
'euc_jis_2004', # 日文 EUC (JIS 2004) / Japanese EUC (JIS 2004)
|
|
50
|
+
'euc_jisx0213', # 日文 EUC (JIS X 0213) / Japanese EUC (JIS X 0213)
|
|
51
|
+
'euc_kr', # 韓文 EUC 編碼 / Korean EUC encoding
|
|
52
|
+
'gb2312', # 簡體中文 (舊標準) / Simplified Chinese (older standard)
|
|
53
|
+
'gbk', # 簡體中文 (擴展) / Simplified Chinese (extended)
|
|
54
|
+
'gb18030', # 簡體中文 (最新國標) / Simplified Chinese (latest national standard)
|
|
55
|
+
'hz', # HZ-GB-2312 (簡體中文, 郵件常用) / Simplified Chinese (email encoding)
|
|
56
|
+
'iso2022_jp', # 日文 ISO-2022-JP / Japanese ISO-2022-JP
|
|
57
|
+
'iso2022_jp_1', # 日文 ISO-2022-JP-1 / Japanese ISO-2022-JP-1
|
|
58
|
+
'iso2022_jp_2', # 日文 ISO-2022-JP-2 / Japanese ISO-2022-JP-2
|
|
59
|
+
'iso2022_jp_2004', # 日文 ISO-2022-JP-2004 / Japanese ISO-2022-JP-2004
|
|
60
|
+
'iso2022_jp_3', # 日文 ISO-2022-JP-3 / Japanese ISO-2022-JP-3
|
|
61
|
+
'iso2022_jp_ext', # 日文 ISO-2022-JP-EXT / Japanese ISO-2022-JP-EXT
|
|
62
|
+
'iso2022_kr', # 韓文 ISO-2022-KR / Korean ISO-2022-KR
|
|
63
|
+
'latin_1', # ISO-8859-1 (西歐語系, 常見) / Western Europe (very common)
|
|
64
|
+
'iso8859_2', # 中歐語系 / Central Europe
|
|
65
|
+
'iso8859_3', # 南歐語系 / South Europe
|
|
66
|
+
'iso8859_4', # 北歐語系 / North Europe
|
|
67
|
+
'iso8859_5', # 西里爾字母 / Cyrillic
|
|
68
|
+
'iso8859_6', # 阿拉伯文 / Arabic
|
|
69
|
+
'iso8859_7', # 希臘文 / Greek
|
|
70
|
+
'iso8859_8', # 希伯來文 / Hebrew
|
|
71
|
+
'iso8859_9', # 土耳其文 / Turkish
|
|
72
|
+
'iso8859_10', # 北歐語系 / Nordic
|
|
73
|
+
'iso8859_11', # 泰文 / Thai
|
|
74
|
+
'iso8859_13', # 波羅的海語系 / Baltic
|
|
75
|
+
'iso8859_14', # 凱爾特語 / Celtic
|
|
76
|
+
'iso8859_15', # 西歐語系 (含歐元) / Western Europe with Euro
|
|
77
|
+
'iso8859_16', # 東歐語系 / Eastern Europe
|
|
78
|
+
'johab', # 韓文 Johab 編碼 / Korean Johab encoding
|
|
79
|
+
'koi8_r', # 俄文 KOI8-R / Russian KOI8-R
|
|
80
|
+
'koi8_t', # 塔吉克文 KOI8-T / Tajik KOI8-T
|
|
81
|
+
'koi8_u', # 烏克蘭文 KOI8-U / Ukrainian KOI8-U
|
|
82
|
+
'kz1048', # 哈薩克文 / Kazakh
|
|
83
|
+
'mac_cyrillic', # Mac OS 西里爾字母 / Mac Cyrillic
|
|
84
|
+
'mac_greek', # Mac OS 希臘文 / Mac Greek
|
|
85
|
+
'mac_iceland', # Mac OS 冰島文 / Mac Icelandic
|
|
86
|
+
'mac_latin2', # Mac OS 中歐語系 / Mac Central Europe
|
|
87
|
+
'mac_roman', # Mac OS 西歐語系 / Mac Roman
|
|
88
|
+
'mac_turkish', # Mac OS 土耳其文 / Mac Turkish
|
|
89
|
+
'ptcp154', # 中亞語系 (西里爾字母) / Central Asian Cyrillic
|
|
90
|
+
'shift_jis', # 日文 Shift JIS 編碼 (常見於 Windows 與網頁) / Japanese Shift JIS encoding (commonly used in Windows & web)
|
|
91
|
+
'shift_jis_2004', # 日文 Shift JIS (JIS 2004 標準) / Japanese Shift JIS (JIS 2004 standard)
|
|
92
|
+
'shift_jisx0213', # 日文 Shift JIS (JIS X 0213 擴展) / Japanese Shift JIS (JIS X 0213 extension)
|
|
93
|
+
'utf_32', # UTF-32 (依平台大小端序, 4 bytes per char) / UTF-32 (platform-dependent endianness, 4 bytes per char)
|
|
94
|
+
'utf_32_be', # UTF-32 Big Endian / UTF-32 大端序
|
|
95
|
+
'utf_32_le', # UTF-32 Little Endian / UTF-32 小端序
|
|
96
|
+
'utf_16', # UTF-16 (依平台大小端序, 2 or 4 bytes per char) / UTF-16 (platform-dependent endianness)
|
|
97
|
+
'utf_16_be', # UTF-16 Big Endian / UTF-16 大端序
|
|
98
|
+
'utf_16_le', # UTF-16 Little Endian / UTF-16 小端序
|
|
99
|
+
'utf_7', # UTF-7 (為電子郵件設計, 已過時) / UTF-7 (designed for email, obsolete)
|
|
100
|
+
'utf_8', # UTF-8 (最常用, 網頁與跨平台標準) / UTF-8 (most common, web & cross-platform standard)
|
|
101
|
+
'utf_8_sig' # UTF-8 with BOM (Byte Order Mark) / UTF-8 含 BOM 標記
|
|
102
|
+
]
|
|
@@ -2,34 +2,51 @@ import typing
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from threading import Lock
|
|
4
4
|
|
|
5
|
+
# 匯入自訂例外與日誌工具
|
|
6
|
+
# Import custom exception and logging utility
|
|
5
7
|
from je_editor.utils.exception.exceptions import JEditorOpenFileException
|
|
6
8
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
7
9
|
|
|
8
10
|
|
|
9
|
-
def read_file(file_path: str) ->
|
|
11
|
+
def read_file(file_path: str) -> list[Path | str] | None:
|
|
10
12
|
"""
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
13
|
+
功能說明 (Function Description):
|
|
14
|
+
用來檢查檔案是否存在並嘗試開啟,讀取其內容。
|
|
15
|
+
Used to check if a file exists and open it to read its content.
|
|
16
|
+
|
|
17
|
+
:param file_path: 檔案完整路徑 / the full path of the file to read
|
|
18
|
+
:return: [檔案路徑, 檔案內容] / [file path, file content]
|
|
19
|
+
|
|
20
|
+
流程 (Logic):
|
|
21
|
+
1. 嘗試鎖定執行緒 (避免多執行緒同時存取)
|
|
22
|
+
Try to lock the thread (prevent concurrent access).
|
|
23
|
+
2. 檢查檔案路徑是否為空,並確認檔案存在且為檔案。
|
|
24
|
+
Check if file path is not empty, exists, and is a file.
|
|
25
|
+
3. 若條件成立,嘗試以 UTF-8 編碼開啟檔案並讀取內容。
|
|
26
|
+
If true, open the file with UTF-8 encoding and read content.
|
|
27
|
+
4. 最後釋放鎖。
|
|
28
|
+
Finally, release the lock.
|
|
22
29
|
"""
|
|
30
|
+
|
|
31
|
+
# 記錄日誌,方便除錯與追蹤
|
|
32
|
+
# Log the file path for debugging and tracking
|
|
23
33
|
jeditor_logger.info(f"open_file.py read_file file_path: {file_path}")
|
|
24
|
-
|
|
34
|
+
|
|
35
|
+
lock = Lock() # 建立一個執行緒鎖 / Create a thread lock
|
|
25
36
|
try:
|
|
26
|
-
lock.acquire()
|
|
27
|
-
if file_path != "" and file_path is not None:
|
|
28
|
-
file_path = Path(file_path)
|
|
29
|
-
if file_path.exists() and file_path.is_file():
|
|
37
|
+
lock.acquire() # 嘗試鎖定資源 / Acquire the lock
|
|
38
|
+
if file_path != "" and file_path is not None: # 確認路徑不為空 / Ensure path is not empty
|
|
39
|
+
file_path = Path(file_path) # 轉換為 Path 物件 / Convert to Path object
|
|
40
|
+
if file_path.exists() and file_path.is_file(): # 檢查檔案存在且為檔案 / Check file existence
|
|
41
|
+
# 以讀寫模式開啟檔案 (UTF-8 編碼)
|
|
42
|
+
# Open file in read+write mode with UTF-8 encoding
|
|
30
43
|
with open(file_path, "r+", encoding="utf-8") as open_read_file:
|
|
31
|
-
return [file_path, open_read_file.read()]
|
|
44
|
+
return [file_path, open_read_file.read()] # 回傳檔案路徑與內容 / Return file path and content
|
|
32
45
|
except JEditorOpenFileException:
|
|
46
|
+
# 捕捉自訂例外並重新拋出
|
|
47
|
+
# Catch custom exception and re-raise
|
|
33
48
|
raise JEditorOpenFileException
|
|
34
49
|
finally:
|
|
35
|
-
|
|
50
|
+
# 確保鎖一定會被釋放
|
|
51
|
+
# Ensure the lock is always released
|
|
52
|
+
lock.release()
|
|
@@ -1,31 +1,52 @@
|
|
|
1
1
|
from threading import Lock
|
|
2
2
|
|
|
3
|
+
# 匯入自訂例外與日誌工具
|
|
4
|
+
# Import custom exception and logging utility
|
|
3
5
|
from je_editor.utils.exception.exceptions import JEditorSaveFileException
|
|
4
6
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
5
7
|
|
|
6
8
|
|
|
7
9
|
def write_file(file_path: str, content: str) -> None:
|
|
8
10
|
"""
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
功能說明 (Function Description):
|
|
12
|
+
將指定內容寫入檔案,並確保在多執行緒環境下安全操作。
|
|
13
|
+
Write the given content into a file, ensuring thread safety.
|
|
14
|
+
|
|
15
|
+
:param file_path: 要寫入的檔案路徑 / the file path to write
|
|
16
|
+
:param content: 要寫入的內容 / the content to write
|
|
17
|
+
|
|
18
|
+
流程 (Logic):
|
|
19
|
+
1. 嘗試鎖定執行緒 (避免多執行緒同時存取檔案)
|
|
20
|
+
Try to lock the thread (prevent concurrent file access).
|
|
21
|
+
2. 檢查檔案路徑是否為空字串或 None。
|
|
22
|
+
Check if file path is not empty or None.
|
|
23
|
+
3. 若條件成立,開啟檔案並以 UTF-8 編碼寫入內容。
|
|
24
|
+
If valid, open the file and write content with UTF-8 encoding.
|
|
25
|
+
4. 最後釋放鎖。
|
|
26
|
+
Finally, release the lock.
|
|
17
27
|
"""
|
|
28
|
+
|
|
29
|
+
# 記錄日誌,方便除錯與追蹤
|
|
30
|
+
# Log the file path and content for debugging and tracking
|
|
18
31
|
jeditor_logger.info("save_file.py write_file "
|
|
19
32
|
f"file_path: {file_path} "
|
|
20
33
|
f"content: {content}")
|
|
21
|
-
|
|
22
|
-
|
|
34
|
+
|
|
35
|
+
lock = Lock() # 建立一個執行緒鎖 / Create a thread lock
|
|
36
|
+
content = str(content) # 確保內容為字串 / Ensure content is a string
|
|
37
|
+
|
|
23
38
|
try:
|
|
24
|
-
lock.acquire()
|
|
25
|
-
if file_path != "" and file_path is not None:
|
|
39
|
+
lock.acquire() # 嘗試鎖定資源 / Acquire the lock
|
|
40
|
+
if file_path != "" and file_path is not None: # 確認路徑有效 / Ensure path is valid
|
|
41
|
+
# 以寫入模式開啟檔案 (UTF-8 編碼)
|
|
42
|
+
# Open file in write+read mode with UTF-8 encoding
|
|
26
43
|
with open(file_path, "w+", encoding="utf-8") as file_to_write:
|
|
27
|
-
file_to_write.write(content)
|
|
44
|
+
file_to_write.write(content) # 寫入內容 / Write content
|
|
28
45
|
except JEditorSaveFileException:
|
|
46
|
+
# 捕捉自訂例外並重新拋出
|
|
47
|
+
# Catch custom exception and re-raise
|
|
29
48
|
raise JEditorSaveFileException
|
|
30
49
|
finally:
|
|
31
|
-
|
|
50
|
+
# 確保鎖一定會被釋放
|
|
51
|
+
# Ensure the lock is always released
|
|
52
|
+
lock.release()
|
|
@@ -1,48 +1,63 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from threading import Lock
|
|
4
|
-
from typing import Union
|
|
4
|
+
from typing import Union, Any
|
|
5
5
|
|
|
6
|
+
# 匯入自訂錯誤訊息與例外類別
|
|
7
|
+
# Import custom error messages and exception class
|
|
6
8
|
from je_editor.utils.exception.exception_tags import cant_find_json_error
|
|
7
9
|
from je_editor.utils.exception.exception_tags import cant_save_json_error
|
|
8
10
|
from je_editor.utils.exception.exceptions import JEditorJsonException
|
|
9
11
|
from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
10
12
|
|
|
13
|
+
# 全域鎖,確保多執行緒存取 JSON 檔案時的安全性
|
|
14
|
+
# Global lock to ensure thread safety when accessing JSON files
|
|
11
15
|
_lock = Lock()
|
|
12
16
|
|
|
13
17
|
|
|
14
|
-
def read_json(json_file_path: str) ->
|
|
18
|
+
def read_json(json_file_path: str) -> Any | None:
|
|
15
19
|
"""
|
|
16
|
-
|
|
17
|
-
|
|
20
|
+
功能說明 (Function Description):
|
|
21
|
+
讀取 JSON 檔案並回傳其內容。
|
|
22
|
+
Read a JSON file and return its content.
|
|
23
|
+
|
|
24
|
+
:param json_file_path: JSON 檔案路徑 / path to the JSON file
|
|
25
|
+
:return: list 或 dict,取決於 JSON 結構 / list or dict depending on JSON structure
|
|
18
26
|
"""
|
|
19
27
|
jeditor_logger.info(f"json_file.py read_json json_file_path: {json_file_path}")
|
|
20
|
-
_lock.acquire()
|
|
28
|
+
_lock.acquire() # 嘗試鎖定資源 / Acquire the lock
|
|
21
29
|
try:
|
|
22
30
|
file_path = Path(json_file_path)
|
|
23
|
-
if file_path.exists() and file_path.is_file():
|
|
24
|
-
with open(json_file_path) as read_file:
|
|
25
|
-
return json.loads(read_file.read())
|
|
31
|
+
if file_path.exists() and file_path.is_file(): # 確認檔案存在且為檔案 / Ensure file exists
|
|
32
|
+
with open(json_file_path) as read_file: # 開啟檔案 (預設 UTF-8)
|
|
33
|
+
return json.loads(read_file.read()) # 載入 JSON 並回傳 / Load JSON and return
|
|
26
34
|
except JEditorJsonException:
|
|
35
|
+
# 捕捉自訂例外並重新拋出
|
|
36
|
+
# Catch custom exception and re-raise
|
|
27
37
|
raise JEditorJsonException(cant_find_json_error)
|
|
28
38
|
finally:
|
|
29
|
-
_lock.release()
|
|
39
|
+
_lock.release() # 確保鎖一定會被釋放 / Ensure the lock is always released
|
|
30
40
|
|
|
31
41
|
|
|
32
42
|
def write_json(json_save_path: str, data_to_output: Union[list, dict]) -> None:
|
|
33
43
|
"""
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
44
|
+
功能說明 (Function Description):
|
|
45
|
+
將資料寫入 JSON 檔案。
|
|
46
|
+
Write data into a JSON file.
|
|
47
|
+
|
|
48
|
+
:param json_save_path: JSON 檔案儲存路徑 / path to save the JSON file
|
|
49
|
+
:param data_to_output: 要輸出的資料 (list 或 dict) / data to output (list or dict)
|
|
37
50
|
"""
|
|
38
51
|
jeditor_logger.info("json_file.py write_json "
|
|
39
52
|
f"json_save_path: {json_save_path} "
|
|
40
53
|
f"data_to_output: {data_to_output}")
|
|
41
|
-
_lock.acquire()
|
|
54
|
+
_lock.acquire() # 嘗試鎖定資源 / Acquire the lock
|
|
42
55
|
try:
|
|
56
|
+
# 以寫入模式開啟檔案,並將資料轉換為 JSON 格式 (縮排 4 格)
|
|
57
|
+
# Open file in write mode and dump data as JSON (indent=4)
|
|
43
58
|
with open(json_save_path, "w+") as file_to_write:
|
|
44
59
|
file_to_write.write(json.dumps(data_to_output, indent=4))
|
|
45
60
|
except JEditorJsonException:
|
|
46
61
|
raise JEditorJsonException(cant_save_json_error)
|
|
47
62
|
finally:
|
|
48
|
-
_lock.release()
|
|
63
|
+
_lock.release() # 確保鎖一定會被釋放 / Ensure the lock is always released
|
|
@@ -3,6 +3,8 @@ import sys
|
|
|
3
3
|
from json import dumps
|
|
4
4
|
from json import loads
|
|
5
5
|
|
|
6
|
+
# 匯入自訂錯誤訊息與例外類別
|
|
7
|
+
# Import custom error messages and exception class
|
|
6
8
|
from je_editor.utils.exception.exception_tags import cant_reformat_json_error
|
|
7
9
|
from je_editor.utils.exception.exception_tags import wrong_json_data_error
|
|
8
10
|
from je_editor.utils.exception.exceptions import JEditorJsonException
|
|
@@ -10,24 +12,53 @@ from je_editor.utils.logging.loggin_instance import jeditor_logger
|
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
def __process_json(json_string: str, **kwargs) -> str:
|
|
15
|
+
"""
|
|
16
|
+
功能說明 (Function Description):
|
|
17
|
+
嘗試將輸入的 JSON 字串重新格式化 (pretty print)。
|
|
18
|
+
Try to reformat the input JSON string (pretty print).
|
|
19
|
+
|
|
20
|
+
:param json_string: JSON 格式字串 / JSON formatted string
|
|
21
|
+
:param kwargs: 額外參數傳給 json.dumps / extra arguments for json.dumps
|
|
22
|
+
:return: 格式化後的 JSON 字串 / formatted JSON string
|
|
23
|
+
"""
|
|
13
24
|
try:
|
|
25
|
+
# 嘗試先將字串解析為 JSON,再重新輸出為縮排格式
|
|
26
|
+
# Try to parse string into JSON, then dump with indentation
|
|
14
27
|
return dumps(loads(json_string), indent=4, sort_keys=True, **kwargs)
|
|
15
28
|
except json.JSONDecodeError as error:
|
|
29
|
+
# 如果 JSON 格式錯誤,輸出錯誤訊息到 stderr 並拋出例外
|
|
30
|
+
# If JSON format is invalid, print error to stderr and raise exception
|
|
16
31
|
print(wrong_json_data_error, file=sys.stderr)
|
|
17
32
|
raise error
|
|
18
33
|
except TypeError:
|
|
34
|
+
# 如果輸入不是合法 JSON 字串,嘗試直接將物件轉為 JSON
|
|
35
|
+
# If input is not a valid JSON string, try dumping the object directly
|
|
19
36
|
try:
|
|
20
37
|
return dumps(json_string, indent=4, sort_keys=True, **kwargs)
|
|
21
38
|
except TypeError:
|
|
39
|
+
# 若仍失敗,拋出自訂例外
|
|
40
|
+
# If still fails, raise custom exception
|
|
22
41
|
raise JEditorJsonException(wrong_json_data_error)
|
|
23
42
|
|
|
24
43
|
|
|
25
44
|
def reformat_json(json_string: str, **kwargs) -> str:
|
|
26
|
-
|
|
45
|
+
"""
|
|
46
|
+
功能說明 (Function Description):
|
|
47
|
+
對外提供的 JSON 格式化函式,會呼叫內部的 __process_json。
|
|
48
|
+
Public function to reformat JSON string, calls __process_json internally.
|
|
49
|
+
|
|
50
|
+
:param json_string: JSON 格式字串 / JSON formatted string
|
|
51
|
+
:param kwargs: 額外參數傳給 json.dumps / extra arguments for json.dumps
|
|
52
|
+
:return: 格式化後的 JSON 字串 / formatted JSON string
|
|
53
|
+
"""
|
|
54
|
+
# 記錄日誌,方便除錯與追蹤
|
|
55
|
+
# Log the input string and kwargs for debugging and tracking
|
|
27
56
|
jeditor_logger.info(f"json_process.py reformat_json "
|
|
28
57
|
f"json_string: {json_string} "
|
|
29
58
|
f"kwargs: {kwargs}")
|
|
30
59
|
try:
|
|
31
60
|
return __process_json(json_string, **kwargs)
|
|
32
61
|
except JEditorJsonException:
|
|
33
|
-
|
|
62
|
+
# 捕捉自訂例外並重新拋出
|
|
63
|
+
# Catch custom exception and re-raise
|
|
64
|
+
raise JEditorJsonException(cant_reformat_json_error)
|