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,16 +1,18 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
1
|
+
from __future__ import annotations # 支援延遲型別註解 (Python 3.7+)
|
|
2
|
+
# Support postponed evaluation of type annotations
|
|
2
3
|
|
|
3
|
-
import queue
|
|
4
|
-
import subprocess
|
|
5
|
-
import sys
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
from threading import Thread
|
|
8
|
-
from typing import Union
|
|
4
|
+
import queue # 佇列,用於執行緒間傳遞訊息
|
|
5
|
+
import subprocess # 建立與管理子程序 (執行外部程式)
|
|
6
|
+
import sys # 系統相關資訊 (平台、參數等)
|
|
7
|
+
from pathlib import Path # 處理檔案與路徑
|
|
8
|
+
from threading import Thread # 執行緒,用於非同步處理
|
|
9
|
+
from typing import Union # 型別提示:允許多種型別
|
|
9
10
|
|
|
10
|
-
from PySide6.QtCore import QTimer
|
|
11
|
-
from PySide6.QtGui import QTextCharFormat
|
|
12
|
-
from PySide6.QtWidgets import QTextEdit
|
|
11
|
+
from PySide6.QtCore import QTimer # Qt 計時器,用於定時觸發事件
|
|
12
|
+
from PySide6.QtGui import QTextCharFormat # 設定文字格式 (顏色、字型等)
|
|
13
|
+
from PySide6.QtWidgets import QTextEdit # 文字編輯器元件
|
|
13
14
|
|
|
15
|
+
# 專案內部模組
|
|
14
16
|
from je_editor.pyside_ui.code.running_process_manager import run_instance_manager
|
|
15
17
|
from je_editor.pyside_ui.main_ui.editor.editor_widget import EditorWidget
|
|
16
18
|
from je_editor.pyside_ui.main_ui.save_settings.user_color_setting_file import actually_color_dict
|
|
@@ -21,45 +23,55 @@ from je_editor.utils.venv_check.check_venv import check_and_choose_venv
|
|
|
21
23
|
|
|
22
24
|
|
|
23
25
|
class ExecManager(object):
|
|
26
|
+
"""
|
|
27
|
+
程式執行管理器
|
|
28
|
+
Execution manager for running code inside the editor.
|
|
29
|
+
負責:
|
|
30
|
+
- 建立子程序 (subprocess)
|
|
31
|
+
- 讀取標準輸出與錯誤輸出
|
|
32
|
+
- 將結果顯示在 QTextEdit
|
|
33
|
+
- 管理計時器與執行緒
|
|
34
|
+
"""
|
|
24
35
|
|
|
25
36
|
def __init__(
|
|
26
37
|
self,
|
|
27
|
-
main_window: Union[EditorWidget, None] = None,
|
|
28
|
-
program_language: str = "python",
|
|
29
|
-
program_encoding: str = "utf-8",
|
|
30
|
-
program_buffer: int = 1024,
|
|
38
|
+
main_window: Union[EditorWidget, None] = None, # 主視窗 (可為 None)
|
|
39
|
+
program_language: str = "python", # 預設程式語言
|
|
40
|
+
program_encoding: str = "utf-8", # 預設編碼
|
|
41
|
+
program_buffer: int = 1024, # 緩衝區大小
|
|
31
42
|
):
|
|
32
43
|
"""
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
:param program_encoding: which encoding
|
|
44
|
+
初始化執行管理器
|
|
45
|
+
Initialize ExecManager
|
|
36
46
|
"""
|
|
37
47
|
jeditor_logger.info(f"Init ExecManager "
|
|
38
48
|
f"main_window: {main_window} "
|
|
39
49
|
f"program_language: {program_language} "
|
|
40
50
|
f"program_encoding: {program_encoding} "
|
|
41
51
|
f"program_buffer: {program_buffer}")
|
|
42
|
-
|
|
43
|
-
self.
|
|
44
|
-
self.
|
|
45
|
-
self.
|
|
46
|
-
self.
|
|
52
|
+
# 初始化屬性
|
|
53
|
+
self.read_program_error_output_from_thread = None # 錯誤輸出讀取執行緒
|
|
54
|
+
self.read_program_output_from_thread = None # 標準輸出讀取執行緒
|
|
55
|
+
self.main_window: EditorWidget = main_window # 主視窗
|
|
56
|
+
self.compiler_path = None # 編譯器/直譯器路徑
|
|
57
|
+
self.code_result: Union[QTextEdit, None] = None # 顯示程式輸出的文字框
|
|
47
58
|
self.code_result_cursor: Union[QTextEdit.textCursor, None] = None
|
|
48
|
-
self.timer: Union[QTimer, None] = None
|
|
49
|
-
self.still_run_program = True
|
|
50
|
-
self.process: Union[subprocess.Popen, None] = None
|
|
51
|
-
self.run_output_queue = queue.Queue()
|
|
52
|
-
self.run_error_queue = queue.Queue()
|
|
59
|
+
self.timer: Union[QTimer, None] = None # 定時器
|
|
60
|
+
self.still_run_program = True # 程式是否仍在執行
|
|
61
|
+
self.process: Union[subprocess.Popen, None] = None # 子程序
|
|
62
|
+
self.run_output_queue = queue.Queue() # 標準輸出佇列
|
|
63
|
+
self.run_error_queue = queue.Queue() # 錯誤輸出佇列
|
|
53
64
|
self.program_language = program_language
|
|
54
65
|
self.program_encoding = program_encoding
|
|
55
66
|
self.program_buffer = program_buffer
|
|
56
|
-
self.renew_path()
|
|
57
|
-
run_instance_manager.instance_list.append(self)
|
|
67
|
+
self.renew_path() # 設定 Python 直譯器路徑
|
|
68
|
+
run_instance_manager.instance_list.append(self) # 註冊到全域執行管理器
|
|
58
69
|
|
|
59
70
|
def renew_path(self) -> None:
|
|
71
|
+
"""更新 Python 直譯器路徑 / Renew compiler path"""
|
|
60
72
|
jeditor_logger.info("ExecManager renew_path")
|
|
61
73
|
if self.main_window.python_compiler is None:
|
|
62
|
-
#
|
|
74
|
+
# 如果主視窗沒有指定 Python,則使用虛擬環境
|
|
63
75
|
if sys.platform in ["win32", "cygwin", "msys"]:
|
|
64
76
|
venv_path = Path(str(Path.cwd()) + "/venv/Scripts")
|
|
65
77
|
else:
|
|
@@ -69,8 +81,8 @@ class ExecManager(object):
|
|
|
69
81
|
self.compiler_path = self.main_window.python_compiler
|
|
70
82
|
|
|
71
83
|
def later_init(self) -> None:
|
|
84
|
+
"""延遲初始化,設定輸出區與計時器 / Setup code result area and timer"""
|
|
72
85
|
jeditor_logger.info("ExecManager later_init")
|
|
73
|
-
# Enable timer and code result area
|
|
74
86
|
if self.main_window is not None:
|
|
75
87
|
self.code_result: QTextEdit = self.main_window.code_result
|
|
76
88
|
self.timer = QTimer(self.main_window)
|
|
@@ -79,34 +91,35 @@ class ExecManager(object):
|
|
|
79
91
|
|
|
80
92
|
def exec_code(self, exec_file_name, exec_prefix: Union[str, list] = None) -> None:
|
|
81
93
|
"""
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
:
|
|
94
|
+
執行指定檔案
|
|
95
|
+
Execute given file
|
|
96
|
+
:param exec_file_name: 要執行的檔案名稱
|
|
97
|
+
:param exec_prefix: 使用者自定義前綴 (例如 python -m)
|
|
85
98
|
"""
|
|
86
99
|
jeditor_logger.info(f"ExecManager exec_code "
|
|
87
100
|
f"exec_file_name: {exec_file_name} "
|
|
88
101
|
f"exec_prefix: {exec_prefix}")
|
|
89
102
|
try:
|
|
90
|
-
self.exit_program()
|
|
91
|
-
self.code_result.setPlainText("")
|
|
103
|
+
self.exit_program() # 確保先結束舊的程式
|
|
104
|
+
self.code_result.setPlainText("") # 清空輸出區
|
|
92
105
|
file_path = Path(exec_file_name)
|
|
93
106
|
reformat_os_file_path = str(file_path.absolute())
|
|
94
|
-
# detect file is exist
|
|
95
107
|
exec_file = reformat_os_file_path
|
|
96
|
-
|
|
108
|
+
|
|
109
|
+
# 建立執行參數
|
|
97
110
|
if exec_prefix is None:
|
|
98
111
|
execute_program_param = [self.compiler_path, exec_file]
|
|
99
112
|
else:
|
|
100
113
|
if isinstance(exec_prefix, str):
|
|
101
114
|
execute_program_param = [self.compiler_path, exec_prefix, exec_file]
|
|
102
115
|
else:
|
|
103
|
-
execute_program_param =
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
execute_program_param.append(prefix)
|
|
107
|
-
execute_program_param.append(exec_file)
|
|
116
|
+
execute_program_param = [self.compiler_path] + exec_prefix + [exec_file]
|
|
117
|
+
|
|
118
|
+
# 非 Windows 平台需轉為字串
|
|
108
119
|
if sys.platform not in ["win32", "cygwin", "msys"]:
|
|
109
120
|
execute_program_param = " ".join(execute_program_param)
|
|
121
|
+
|
|
122
|
+
# 建立子程序
|
|
110
123
|
self.process = subprocess.Popen(
|
|
111
124
|
execute_program_param,
|
|
112
125
|
stdout=subprocess.PIPE,
|
|
@@ -115,31 +128,36 @@ class ExecManager(object):
|
|
|
115
128
|
shell=False
|
|
116
129
|
)
|
|
117
130
|
self.still_run_program = True
|
|
118
|
-
|
|
131
|
+
|
|
132
|
+
# 啟動輸出讀取執行緒
|
|
119
133
|
self.read_program_output_from_thread = Thread(
|
|
120
134
|
target=self.read_program_output_from_process,
|
|
121
135
|
daemon=True
|
|
122
136
|
)
|
|
123
137
|
self.read_program_output_from_thread.start()
|
|
124
|
-
|
|
138
|
+
|
|
139
|
+
# 啟動錯誤讀取執行緒
|
|
125
140
|
self.read_program_error_output_from_thread = Thread(
|
|
126
141
|
target=self.read_program_error_output_from_process,
|
|
127
142
|
daemon=True
|
|
128
143
|
)
|
|
129
144
|
self.read_program_error_output_from_thread.start()
|
|
130
|
-
|
|
145
|
+
|
|
146
|
+
# 顯示執行的檔案路徑
|
|
131
147
|
text_cursor = self.code_result.textCursor()
|
|
132
148
|
text_format = QTextCharFormat()
|
|
133
149
|
text_format.setForeground(actually_color_dict.get("normal_output_color"))
|
|
134
150
|
text_cursor.insertText(self.compiler_path + " " + reformat_os_file_path, text_format)
|
|
135
151
|
text_cursor.insertBlock()
|
|
136
|
-
|
|
137
|
-
#
|
|
152
|
+
|
|
153
|
+
# 啟動定時器,每 10ms 更新輸出
|
|
138
154
|
self.timer = QTimer(self.main_window)
|
|
139
155
|
self.timer.setInterval(10)
|
|
140
156
|
self.timer.timeout.connect(self.pull_text)
|
|
141
157
|
self.timer.start()
|
|
158
|
+
|
|
142
159
|
except Exception as error:
|
|
160
|
+
# 發生錯誤時顯示錯誤訊息
|
|
143
161
|
text_cursor = self.code_result.textCursor()
|
|
144
162
|
text_format = QTextCharFormat()
|
|
145
163
|
text_format.setForeground(actually_color_dict.get("normal_output_color"))
|
|
@@ -149,6 +167,7 @@ class ExecManager(object):
|
|
|
149
167
|
self.process.terminate()
|
|
150
168
|
|
|
151
169
|
def full_exit_program(self):
|
|
170
|
+
"""完全結束程式 / Fully exit program"""
|
|
152
171
|
jeditor_logger.info("ExecManager full_exit_program")
|
|
153
172
|
self.timer.stop()
|
|
154
173
|
self.exit_program()
|
|
@@ -156,8 +175,10 @@ class ExecManager(object):
|
|
|
156
175
|
|
|
157
176
|
def pull_text(self) -> None:
|
|
158
177
|
jeditor_logger.info("ExecManager pull_text")
|
|
178
|
+
# 從佇列中取出訊息並顯示到 QTextEdit
|
|
159
179
|
# Pull text from queue and put in code result area
|
|
160
180
|
try:
|
|
181
|
+
# 處理標準輸出
|
|
161
182
|
if not self.run_output_queue.empty():
|
|
162
183
|
output_message = self.run_output_queue.get_nowait()
|
|
163
184
|
output_message = str(output_message).strip()
|
|
@@ -167,6 +188,7 @@ class ExecManager(object):
|
|
|
167
188
|
text_format.setForeground(actually_color_dict.get("normal_output_color"))
|
|
168
189
|
text_cursor.insertText(output_message, text_format)
|
|
169
190
|
text_cursor.insertBlock()
|
|
191
|
+
# 處理錯誤輸出
|
|
170
192
|
if not self.run_error_queue.empty():
|
|
171
193
|
error_message = self.run_error_queue.get_nowait()
|
|
172
194
|
error_message = str(error_message).strip()
|
|
@@ -177,24 +199,33 @@ class ExecManager(object):
|
|
|
177
199
|
text_cursor.insertText(error_message, text_format)
|
|
178
200
|
text_cursor.insertBlock()
|
|
179
201
|
except queue.Empty:
|
|
202
|
+
# 如果佇列是空的就忽略
|
|
180
203
|
pass
|
|
204
|
+
|
|
205
|
+
# 如果子程序已經結束(returncode 不為 None),則完全退出
|
|
181
206
|
if self.process.returncode == 0:
|
|
182
207
|
self.full_exit_program()
|
|
183
208
|
elif self.process.returncode is not None:
|
|
184
209
|
self.full_exit_program()
|
|
210
|
+
|
|
211
|
+
# 如果程式仍在執行,持續檢查狀態
|
|
185
212
|
if self.still_run_program:
|
|
186
|
-
# poll
|
|
213
|
+
# poll() 不會阻塞,只是更新 returncode
|
|
187
214
|
self.process.poll()
|
|
188
215
|
|
|
189
|
-
#
|
|
216
|
+
# 結束程式:將執行旗標設為 False,清理執行緒、佇列與子程序
|
|
217
|
+
# Exit program: change run flag to false and clean read thread, queue, and process
|
|
190
218
|
def exit_program(self) -> None:
|
|
191
219
|
jeditor_logger.info("ExecManager exit_program")
|
|
192
220
|
self.still_run_program = False
|
|
221
|
+
# 清除讀取執行緒的引用
|
|
193
222
|
if self.read_program_output_from_thread is not None:
|
|
194
223
|
self.read_program_output_from_thread = None
|
|
195
224
|
if self.read_program_error_output_from_thread is not None:
|
|
196
225
|
self.read_program_error_output_from_thread = None
|
|
226
|
+
# 清空佇列
|
|
197
227
|
self.print_and_clear_queue()
|
|
228
|
+
# 如果子程序存在,則終止
|
|
198
229
|
if self.process is not None:
|
|
199
230
|
self.process.terminate()
|
|
200
231
|
text_cursor = self.code_result.textCursor()
|
|
@@ -204,12 +235,15 @@ class ExecManager(object):
|
|
|
204
235
|
text_cursor.insertBlock()
|
|
205
236
|
self.process = None
|
|
206
237
|
|
|
207
|
-
#
|
|
238
|
+
# 清空輸出與錯誤佇列
|
|
239
|
+
# Pull all remaining strings in queues and reset them
|
|
208
240
|
def print_and_clear_queue(self) -> None:
|
|
209
241
|
jeditor_logger.info("ExecManager print_and_clear_queue")
|
|
210
242
|
self.run_output_queue = queue.Queue()
|
|
211
243
|
self.run_error_queue = queue.Queue()
|
|
212
244
|
|
|
245
|
+
# 從子程序 stdout 持續讀取資料並放入輸出佇列
|
|
246
|
+
# Continuously read from process stdout and put into output queue
|
|
213
247
|
def read_program_output_from_process(self) -> None:
|
|
214
248
|
jeditor_logger.info("ExecManager read_program_output_from_process")
|
|
215
249
|
while self.still_run_program:
|
|
@@ -219,6 +253,8 @@ class ExecManager(object):
|
|
|
219
253
|
self.process.stdout.flush()
|
|
220
254
|
self.run_output_queue.put_nowait(program_output_data)
|
|
221
255
|
|
|
256
|
+
# 從子程序 stderr 持續讀取資料並放入錯誤佇列
|
|
257
|
+
# Continuously read from process stderr and put into error queue
|
|
222
258
|
def read_program_error_output_from_process(self) -> None:
|
|
223
259
|
jeditor_logger.info("ExecManager read_program_error_output_from_process")
|
|
224
260
|
while self.still_run_program:
|
|
@@ -226,4 +262,4 @@ class ExecManager(object):
|
|
|
226
262
|
self.program_buffer).decode(self.program_encoding, "replace")
|
|
227
263
|
if self.process:
|
|
228
264
|
self.process.stderr.flush()
|
|
229
|
-
self.run_error_queue.put_nowait(program_error_output_data)
|
|
265
|
+
self.run_error_queue.put_nowait(program_error_output_data)
|