je-editor 0.0.223__py3-none-any.whl → 0.0.224__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (71) hide show
  1. je_editor/git_client/commit_graph.py +7 -7
  2. je_editor/git_client/git_action.py +0 -7
  3. je_editor/pyside_ui/browser/browser_widget.py +24 -11
  4. je_editor/pyside_ui/browser/main_browser_widget.py +40 -27
  5. je_editor/pyside_ui/code/auto_save/auto_save_manager.py +34 -2
  6. je_editor/pyside_ui/code/auto_save/auto_save_thread.py +19 -6
  7. je_editor/pyside_ui/code/code_format/pep8_format.py +53 -9
  8. je_editor/pyside_ui/code/code_process/code_exec.py +88 -52
  9. je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +116 -55
  10. je_editor/pyside_ui/code/running_process_manager.py +19 -1
  11. je_editor/pyside_ui/code/shell_process/shell_exec.py +71 -48
  12. je_editor/pyside_ui/code/syntax/python_syntax.py +45 -10
  13. je_editor/pyside_ui/code/syntax/syntax_setting.py +40 -12
  14. je_editor/pyside_ui/code/textedit_code_result/code_record.py +34 -12
  15. je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +53 -6
  16. je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +30 -3
  17. je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +35 -2
  18. je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +33 -5
  19. je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +25 -3
  20. je_editor/pyside_ui/dialog/search_ui/search_error_box.py +26 -1
  21. je_editor/pyside_ui/dialog/search_ui/search_text_box.py +26 -1
  22. je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +11 -11
  23. je_editor/pyside_ui/git_ui/git_client/commit_table.py +46 -8
  24. je_editor/pyside_ui/git_ui/git_client/git_branch_tree_widget.py +49 -15
  25. je_editor/pyside_ui/git_ui/git_client/graph_view.py +64 -20
  26. je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +20 -5
  27. je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +20 -1
  28. je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +56 -41
  29. je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +45 -6
  30. je_editor/pyside_ui/main_ui/console_widget/console_gui.py +44 -12
  31. je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +34 -13
  32. je_editor/pyside_ui/main_ui/dock/destroy_dock.py +33 -2
  33. je_editor/pyside_ui/main_ui/editor/editor_widget.py +104 -20
  34. je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +34 -7
  35. je_editor/pyside_ui/main_ui/editor/process_input.py +38 -11
  36. je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +46 -11
  37. je_editor/pyside_ui/main_ui/main_editor.py +175 -37
  38. je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +51 -28
  39. je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +80 -22
  40. je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +70 -17
  41. je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +34 -3
  42. je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +41 -1
  43. je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +100 -42
  44. je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +57 -7
  45. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +50 -4
  46. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +52 -6
  47. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +44 -4
  48. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +23 -1
  49. je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +37 -12
  50. je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +44 -7
  51. je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +126 -28
  52. je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +65 -1
  53. je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +18 -1
  54. je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +33 -3
  55. je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +38 -11
  56. je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +39 -2
  57. je_editor/start_editor.py +26 -1
  58. je_editor/utils/encodings/python_encodings.py +101 -98
  59. je_editor/utils/file/open/open_file.py +36 -19
  60. je_editor/utils/file/save/save_file.py +35 -14
  61. je_editor/utils/json/json_file.py +29 -14
  62. je_editor/utils/json_format/json_process.py +33 -2
  63. je_editor/utils/logging/loggin_instance.py +38 -8
  64. je_editor/utils/multi_language/multi_language_wrapper.py +29 -4
  65. je_editor/utils/redirect_manager/redirect_manager_class.py +49 -11
  66. je_editor/utils/venv_check/check_venv.py +45 -15
  67. {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/METADATA +1 -1
  68. {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/RECORD +71 -71
  69. {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/WHEEL +0 -0
  70. {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/licenses/LICENSE +0 -0
  71. {je_editor-0.0.223.dist-info → je_editor-0.0.224.dist-info}/top_level.txt +0 -0
@@ -5,17 +5,21 @@ from typing import TYPE_CHECKING
5
5
 
6
6
  from je_editor.utils.logging.loggin_instance import jeditor_logger
7
7
 
8
+ # 僅在型別檢查時匯入,避免循環引用
9
+ # Only imported for type checking, avoids circular imports
8
10
  if TYPE_CHECKING:
9
11
  from je_editor.pyside_ui.main_ui.editor.editor_widget import EditorWidget
10
12
  from je_editor.pyside_ui.main_ui.editor.editor_widget_dock import FullEditorWidget
11
13
 
12
14
  from typing import Union, List
13
15
 
14
- import jedi
16
+ import jedi # Python 自動補全與靜態分析工具
15
17
  from PySide6 import QtGui
16
18
  from PySide6.QtCore import Qt, QRect
17
- from PySide6.QtGui import QPainter, QTextCharFormat, QTextFormat, QKeyEvent, QAction, QTextDocument, QTextCursor, \
18
- QTextOption
19
+ from PySide6.QtGui import (
20
+ QPainter, QTextCharFormat, QTextFormat, QKeyEvent, QAction,
21
+ QTextDocument, QTextCursor, QTextOption
22
+ )
19
23
  from PySide6.QtWidgets import QPlainTextEdit, QWidget, QTextEdit, QCompleter
20
24
  from jedi.api.classes import Completion
21
25
 
@@ -25,6 +29,7 @@ from je_editor.pyside_ui.main_ui.save_settings.user_color_setting_file import ac
25
29
 
26
30
 
27
31
  def venv_check():
32
+ """檢查當前工作目錄下是否有 venv 資料夾 / Check if venv exists in current working directory"""
28
33
  jeditor_logger.info("code_edit_plaintext.py venv check")
29
34
  venv_path = Path(str(Path.cwd()) + "/venv")
30
35
  return venv_path
@@ -32,24 +37,36 @@ def venv_check():
32
37
 
33
38
  class CodeEditor(QPlainTextEdit):
34
39
  """
35
- Extend QPlainTextEdit,
36
- Add line, edit tab distance, add highlighter, add search text
40
+ 自訂的程式碼編輯器,繼承 QPlainTextEdit
41
+ Custom code editor extending QPlainTextEdit
42
+
43
+ 功能:
44
+ - 行號顯示 (Line number area)
45
+ - Tab 縮排距離設定
46
+ - Python 語法高亮 (Syntax highlighting)
47
+ - 搜尋功能 (Search box)
48
+ - 自動補全 (Autocomplete with Jedi)
37
49
  """
38
50
 
39
51
  def __init__(self, main_window: Union[EditorWidget, FullEditorWidget]):
40
52
  jeditor_logger.info(f"Init CodeEditor main_window: {main_window}")
41
53
  super().__init__()
42
- # Jedi
54
+
55
+ # Jedi 環境,用於 Python 自動補全
43
56
  self.env = None
44
57
  self.check_env()
45
- # Self main window (parent)
58
+
59
+ # 主視窗 (父元件)
46
60
  self.main_window = main_window
47
61
  self.current_file = main_window.current_file
48
62
 
63
+ # 定義哪些按鍵不會觸發補全視窗
49
64
  self.skip_popup_behavior_list = [
50
65
  Qt.Key.Key_Enter, Qt.Key.Key_Return, Qt.Key.Key_Up, Qt.Key.Key_Down,
51
66
  Qt.Key.Key_Tab, Qt.Key.Key_Backtab, Qt.Key.Key_Space, Qt.Key.Key_Backspace
52
67
  ]
68
+
69
+ # 定義哪些按鍵會觸發補全 (A-Z)
53
70
  self.need_complete_list = [
54
71
  Qt.Key.Key_A, Qt.Key.Key_B, Qt.Key.Key_C, Qt.Key.Key_D, Qt.Key.Key_E, Qt.Key.Key_F,
55
72
  Qt.Key.Key_G, Qt.Key.Key_H, Qt.Key.Key_I, Qt.Key.Key_J, Qt.Key.Key_K, Qt.Key.Key_L,
@@ -57,37 +74,50 @@ class CodeEditor(QPlainTextEdit):
57
74
  Qt.Key.Key_S, Qt.Key.Key_T, Qt.Key.Key_U, Qt.Key.Key_V, Qt.Key.Key_W, Qt.Key.Key_X,
58
75
  Qt.Key.Key_Y, Qt.Key.Key_Z
59
76
  ]
77
+
78
+ # 搜尋框 (延遲建立)
60
79
  self.search_box = None
80
+
81
+ # 行號區域 (LineNumber 是另一個自訂類別)
61
82
  self.line_number: LineNumber = LineNumber(self)
62
83
  self.blockCountChanged.connect(self.update_line_number_area_width)
63
84
  self.updateRequest.connect(self.update_line_number_area)
64
85
  self.update_line_number_area_width(0)
86
+
87
+ # 當文字改變時,重新高亮當前行
65
88
  self.textChanged.connect(self.highlight_current_line)
89
+
90
+ # 設定 Tab 寬度 (以字元寬度計算)
66
91
  self.setTabStopDistance(
67
92
  QtGui.QFontMetricsF(self.font()).horizontalAdvance(" ")
68
93
  )
94
+
95
+ # Python 語法高亮
69
96
  self.highlighter = PythonHighlighter(self.document(), main_window=self)
70
97
  self.highlight_current_line()
98
+
99
+ # 關閉自動換行,改為單行顯示
71
100
  self.setLineWrapMode(self.LineWrapMode.NoWrap)
72
101
  self.setWordWrapMode(QTextOption.WrapMode.WrapAnywhere)
73
- # Search Text
102
+
103
+ # 搜尋功能 (Ctrl+F)
74
104
  self.search_action = QAction("Search")
75
105
  self.search_action.setShortcut("Ctrl+f")
76
- self.search_action.triggered.connect(
77
- self.start_search_dialog
78
- )
79
- # Add actions
106
+ self.search_action.triggered.connect(self.start_search_dialog)
80
107
  self.addAction(self.search_action)
81
- # Complete
108
+
109
+ # 自動補全初始化
82
110
  self.completer: Union[None, QCompleter] = None
83
111
  self.set_complete([])
84
112
 
85
113
  def reset_highlighter(self):
114
+ """重設語法高亮 / Reset syntax highlighter"""
86
115
  jeditor_logger.info("CodeEditor reset_highlighter")
87
116
  self.highlighter = PythonHighlighter(self.document(), main_window=self)
88
117
  self.highlight_current_line()
89
118
 
90
119
  def check_env(self):
120
+ """檢查虛擬環境並建立 Jedi 環境 / Check venv and create Jedi environment"""
91
121
  jeditor_logger.info("CodeEditor check_env")
92
122
  path = venv_check()
93
123
  if path.exists():
@@ -95,9 +125,8 @@ class CodeEditor(QPlainTextEdit):
95
125
 
96
126
  def set_complete(self, list_to_complete: list) -> None:
97
127
  """
98
- Set complete and bind.
99
- :param list_to_complete: keyword list to complete.
100
- :return: None
128
+ 設定自動補全清單
129
+ Set completion list
101
130
  """
102
131
  jeditor_logger.info(f"CodeEditor set_complete list_to_complete: {list_to_complete}")
103
132
  completer = QCompleter(list_to_complete)
@@ -110,9 +139,8 @@ class CodeEditor(QPlainTextEdit):
110
139
 
111
140
  def insert_completion(self, completion) -> None:
112
141
  """
113
- insert complete keyword to editor.
114
- :param completion: completion text
115
- :return: None
142
+ 插入補全文字
143
+ Insert completion text into editor
116
144
  """
117
145
  jeditor_logger.info(f"CodeEditor insert_completion completion: {completion}")
118
146
  if self.completer.widget() != self:
@@ -126,13 +154,14 @@ class CodeEditor(QPlainTextEdit):
126
154
 
127
155
  @property
128
156
  def text_under_cursor(self):
157
+ """取得游標下的文字 / Get text under cursor"""
129
158
  jeditor_logger.info("CodeEditor text_under_cursor")
130
- # Find text under cursor
131
159
  text_cursor = self.textCursor()
132
160
  text_cursor.select(QTextCursor.SelectionType.WordUnderCursor)
133
161
  return text_cursor.selectedText()
134
162
 
135
163
  def focusInEvent(self, e) -> None:
164
+ """當編輯器獲得焦點時,確保 completer 綁定正確"""
136
165
  jeditor_logger.info(f"CodeEditor focusInEvent event: {e}")
137
166
  if self.completer:
138
167
  self.completer.setWidget(self)
@@ -140,8 +169,8 @@ class CodeEditor(QPlainTextEdit):
140
169
 
141
170
  def complete(self) -> None:
142
171
  """
143
- Keyword autocomplete
144
- :return: None
172
+ 使用 Jedi 進行自動補全
173
+ Keyword autocomplete with Jedi
145
174
  """
146
175
  jeditor_logger.info("CodeEditor complete")
147
176
  prefix = self.text_under_cursor
@@ -149,15 +178,18 @@ class CodeEditor(QPlainTextEdit):
149
178
  script = jedi.Script(code=self.toPlainText(), environment=self.env)
150
179
  else:
151
180
  script = jedi.Script(code=self.toPlainText())
181
+
182
+ # 取得補全清單
152
183
  jedi_complete_list: List[Completion] = script.complete(
153
184
  self.textCursor().blockNumber() + 1,
154
185
  len(self.textCursor().document().findBlockByLineNumber(self.textCursor().blockNumber()).text())
155
186
  )
187
+
156
188
  if len(jedi_complete_list) > 0:
157
- new_complete_list = list()
158
- for complete_text in jedi_complete_list:
159
- new_complete_list.append(complete_text.name)
189
+ new_complete_list = [complete_text.name for complete_text in jedi_complete_list]
160
190
  self.set_complete(new_complete_list)
191
+
192
+ # 顯示補全視窗
161
193
  self.completer.setCompletionPrefix(prefix)
162
194
  popup = self.completer.popup()
163
195
  cursor_rect = self.cursorRect()
@@ -166,16 +198,10 @@ class CodeEditor(QPlainTextEdit):
166
198
  self.completer.complete(cursor_rect)
167
199
 
168
200
  def start_search_dialog(self) -> None:
169
- """
170
- Show search box ui and bind.
171
- :return: None
172
- """
201
+ """顯示搜尋框 / Show search box"""
173
202
  jeditor_logger.info("CodeEditor start_search_dialog")
174
- # Search box connect to function
175
203
  self.search_box = SearchBox()
176
- self.search_box.search_back_button.clicked.connect(
177
- self.find_back_text
178
- )
204
+ self.search_box.search_back_button.clicked.connect(self.find_back_text)
179
205
  self.search_box.search_next_button.clicked.connect(
180
206
  self.find_next_text
181
207
  )
@@ -183,8 +209,8 @@ class CodeEditor(QPlainTextEdit):
183
209
 
184
210
  def find_next_text(self) -> None:
185
211
  """
186
- Find next match text.
187
- :return: None
212
+ 找到下一個符合的文字
213
+ Find next match text
188
214
  """
189
215
  jeditor_logger.info("CodeEditor find_next_text")
190
216
  if self.search_box.isVisible():
@@ -193,8 +219,8 @@ class CodeEditor(QPlainTextEdit):
193
219
 
194
220
  def find_back_text(self) -> None:
195
221
  """
196
- Find back match text.
197
- :return: None
222
+ 找到上一個符合的文字
223
+ Find previous match text
198
224
  """
199
225
  jeditor_logger.info("CodeEditor find_back_text")
200
226
  if self.search_box.isVisible():
@@ -202,13 +228,22 @@ class CodeEditor(QPlainTextEdit):
202
228
  self.find(text, QTextDocument.FindFlag.FindBackward)
203
229
 
204
230
  def line_number_paint(self, event) -> None:
231
+ """
232
+ 繪製行號區域
233
+ Paint line number area
234
+ """
205
235
  jeditor_logger.info(f"CodeEditor line_number_paint event: {event}")
206
236
  painter = QPainter(self.line_number)
237
+ # 填滿背景色
207
238
  painter.fillRect(event.rect(), actually_color_dict.get("line_number_background_color"))
239
+
240
+ # 從第一個可見區塊開始
208
241
  block = self.firstVisibleBlock()
209
242
  block_number = block.blockNumber()
210
243
  top = self.blockBoundingGeometry(block).translated(self.contentOffset()).top()
211
244
  bottom = top + self.blockBoundingRect(block).height()
245
+
246
+ # 逐行繪製行號
212
247
  while block.isValid() and top <= event.rect().bottom():
213
248
  if block.isVisible() and bottom >= event.rect().top():
214
249
  number = str(block_number + 1)
@@ -227,20 +262,27 @@ class CodeEditor(QPlainTextEdit):
227
262
  block_number += 1
228
263
 
229
264
  def line_number_width(self) -> int:
265
+ """
266
+ 計算行號區域寬度
267
+ Calculate line number area width
268
+ """
230
269
  jeditor_logger.info("CodeEditor line_number_width")
231
- digits = len(str(self.blockCount()))
270
+ digits = len(str(self.blockCount())) # 根據總行數決定位數
232
271
  space = 12 * digits
233
272
  return space
234
273
 
235
274
  def update_line_number_area_width(self, value) -> None:
275
+ """
276
+ 更新行號區域寬度
277
+ Update line number area width
278
+ """
236
279
  jeditor_logger.info(f"CodeEditor update_line_number_area_width value: {value}")
237
280
  self.setViewportMargins(self.line_number_width(), 0, 0, 0)
238
281
 
239
282
  def resizeEvent(self, event) -> None:
240
283
  """
241
- Resize line number paint.
242
- :param event: QT event.
243
- :return: None
284
+ 視窗大小改變時,調整行號區域
285
+ Resize line number paint area
244
286
  """
245
287
  jeditor_logger.info(f"CodeEditor resizeEvent event:{event}")
246
288
  QPlainTextEdit.resizeEvent(self, event)
@@ -251,10 +293,8 @@ class CodeEditor(QPlainTextEdit):
251
293
 
252
294
  def update_line_number_area(self, rect, dy) -> None:
253
295
  """
254
- Set line number.
255
- :param rect: line number rect.
256
- :param dy: update or not.
257
- :return: None
296
+ 更新行號顯示
297
+ Update line number area
258
298
  """
259
299
  jeditor_logger.info(f"CodeEditor update_line_number_area rect: {rect}, dy: {dy}")
260
300
  if dy:
@@ -271,8 +311,8 @@ class CodeEditor(QPlainTextEdit):
271
311
 
272
312
  def highlight_current_line(self) -> None:
273
313
  """
274
- Change current line color.
275
- :return: None
314
+ 高亮目前所在行
315
+ Highlight current line
276
316
  """
277
317
  jeditor_logger.info("CodeEditor highlight_current_line")
278
318
  selections = []
@@ -290,13 +330,16 @@ class CodeEditor(QPlainTextEdit):
290
330
 
291
331
  def keyPressEvent(self, event: QKeyEvent) -> None:
292
332
  """
293
- Catch Soft new line (key, shift + enter)
294
- :param event: keypress event
295
- :return: None
333
+ 鍵盤事件處理
334
+ Handle key press events
335
+ - Ctrl+B: 使用 Jedi 跳轉定義
336
+ - Shift+Enter: 忽略軟換行
337
+ - 其他情況觸發自動補全
296
338
  """
297
- # Catch soft wrap shift + return (line nuber not working on soft warp)
298
339
  key = event.key()
299
340
  jeditor_logger.info(f"CodeEditor keyPressEvent event: {event} key: {key}")
341
+
342
+ # Ctrl + B → 跳轉到定義
300
343
  if event.modifiers() and Qt.Modifier.CTRL:
301
344
  if key == Qt.Key.Key_B:
302
345
  if self.env is not None:
@@ -313,31 +356,45 @@ class CodeEditor(QPlainTextEdit):
313
356
  else:
314
357
  self.textCursor().setPosition(goto_list[0].line - 1)
315
358
  return
359
+
360
+ # 如果補全視窗開啟,且按下不該觸發的按鍵 → 關閉補全
316
361
  if self.completer.popup().isVisible() and key in self.skip_popup_behavior_list:
317
362
  self.completer.popup().close()
318
363
  event.ignore()
319
364
  return
365
+
366
+ # Shift+Enter → 忽略 (避免軟換行影響行號)
320
367
  if event.modifiers() and Qt.Modifier.SHIFT:
321
368
  if key == Qt.Key.Key_Enter or key == Qt.Key.Key_Return:
322
369
  event.ignore()
323
370
  return
371
+
372
+ # 呼叫父類別處理其他按鍵
324
373
  super().keyPressEvent(event)
374
+
375
+ # 更新目前行高亮
325
376
  self.highlight_current_line()
377
+
378
+ # 如果輸入英文字母,觸發自動補全
326
379
  if key in self.need_complete_list and self.completer is not None:
327
380
  if self.completer.popup().isVisible():
328
381
  self.completer.popup().close()
329
382
  self.complete()
330
383
 
331
384
  def mousePressEvent(self, event) -> None:
385
+ """
386
+ 滑鼠點擊事件
387
+ Mouse press event
388
+ - 點擊後高亮所在行
389
+ """
332
390
  jeditor_logger.info(f"CodeEditor mousePressEvent event: {event}")
333
- # Highlight mouse click line
334
391
  super().mousePressEvent(event)
335
392
  self.highlight_current_line()
336
393
 
337
-
338
394
  class LineNumber(QWidget):
339
395
  """
340
- Used to paint line number.
396
+ 行號區域元件
397
+ Widget used to paint line numbers
341
398
  """
342
399
 
343
400
  def __init__(self, editor):
@@ -346,5 +403,9 @@ class LineNumber(QWidget):
346
403
  self.editor = editor
347
404
 
348
405
  def paintEvent(self, event) -> None:
406
+ """
407
+ 呼叫編輯器的 line_number_paint 來繪製行號
408
+ Delegate painting to CodeEditor.line_number_paint
409
+ """
349
410
  jeditor_logger.info(f"LineNumber paintEvent event: {event}")
350
- self.editor.line_number_paint(event)
411
+ self.editor.line_number_paint(event)
@@ -5,6 +5,8 @@ from typing import TYPE_CHECKING
5
5
  from je_editor.utils.logging.loggin_instance import jeditor_logger
6
6
 
7
7
  if TYPE_CHECKING:
8
+ # 僅在型別檢查時匯入,避免循環依賴
9
+ # Only imported during type checking to avoid circular imports
8
10
  from je_editor.pyside_ui.code.code_process.code_exec import ExecManager
9
11
  from je_editor.pyside_ui.code.shell_process.shell_exec import ShellManager
10
12
 
@@ -12,19 +14,35 @@ from typing import List, Union
12
14
 
13
15
 
14
16
  class RunInstanceManager(object):
17
+ """
18
+ 管理程式執行與 Shell 執行的實例
19
+ Manager for ExecManager and ShellManager instances
20
+ """
15
21
 
16
22
  def __init__(self):
23
+ # 初始化,建立一個空的實例清單
24
+ # Initialize with an empty instance list
17
25
  jeditor_logger.info("Init RunInstanceManager")
18
26
  self.instance_list: List[Union[ExecManager, ShellManager]] = list()
19
27
 
20
28
  def close_all_instance(self):
29
+ """
30
+ 關閉所有執行中的實例,並清理 main_window 的執行狀態
31
+ Close all running instances and reset main_window execution states
32
+ """
21
33
  jeditor_logger.info("RunInstanceManager close_all_instance")
22
34
  for manager in self.instance_list:
35
+ # 若子程序仍存在,則終止
36
+ # Terminate process if still running
23
37
  if manager.process is not None:
24
38
  manager.process.terminate()
39
+ # 清理 main_window 的執行狀態
40
+ # Reset execution states in main_window
25
41
  manager.main_window.exec_program = None
26
42
  manager.main_window.exec_shell = None
27
43
  manager.main_window.exec_python_debugger = None
28
44
 
29
45
 
30
- run_instance_manager = RunInstanceManager()
46
+ # 建立全域唯一的 RunInstanceManager 實例
47
+ # Create a global singleton instance of RunInstanceManager
48
+ run_instance_manager = RunInstanceManager()