je-editor 0.0.202__py3-none-any.whl → 0.0.228__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. je_editor/__init__.py +2 -2
  2. je_editor/code_scan/__init__.py +0 -0
  3. je_editor/code_scan/ruff_thread.py +58 -0
  4. je_editor/code_scan/watchdog_implement.py +56 -0
  5. je_editor/code_scan/watchdog_thread.py +78 -0
  6. je_editor/git_client/__init__.py +0 -0
  7. je_editor/git_client/commit_graph.py +77 -0
  8. je_editor/git_client/git_action.py +175 -0
  9. je_editor/git_client/git_cli.py +66 -0
  10. je_editor/pyside_ui/browser/browser_download_window.py +40 -4
  11. je_editor/pyside_ui/browser/browser_serach_lineedit.py +24 -0
  12. je_editor/pyside_ui/browser/browser_view.py +55 -6
  13. je_editor/pyside_ui/browser/browser_widget.py +62 -19
  14. je_editor/pyside_ui/browser/main_browser_widget.py +85 -0
  15. je_editor/pyside_ui/code/auto_save/auto_save_manager.py +33 -1
  16. je_editor/pyside_ui/code/auto_save/auto_save_thread.py +18 -5
  17. je_editor/pyside_ui/code/code_format/pep8_format.py +52 -7
  18. je_editor/pyside_ui/code/code_process/code_exec.py +118 -64
  19. je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +115 -53
  20. je_editor/pyside_ui/code/running_process_manager.py +18 -0
  21. je_editor/pyside_ui/code/shell_process/shell_exec.py +99 -60
  22. je_editor/pyside_ui/code/syntax/python_syntax.py +44 -9
  23. je_editor/pyside_ui/code/syntax/syntax_setting.py +39 -11
  24. je_editor/pyside_ui/code/textedit_code_result/code_record.py +33 -11
  25. je_editor/pyside_ui/code/variable_inspector/__init__.py +0 -0
  26. je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +172 -0
  27. je_editor/pyside_ui/dialog/ai_dialog/__init__.py +0 -0
  28. je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +71 -0
  29. je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +38 -4
  30. je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +32 -4
  31. je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +25 -2
  32. je_editor/pyside_ui/dialog/search_ui/search_error_box.py +27 -2
  33. je_editor/pyside_ui/dialog/search_ui/search_text_box.py +28 -3
  34. je_editor/pyside_ui/git_ui/__init__.py +0 -0
  35. je_editor/pyside_ui/git_ui/code_diff_compare/__init__.py +0 -0
  36. je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +90 -0
  37. je_editor/pyside_ui/git_ui/code_diff_compare/line_number_code_viewer.py +141 -0
  38. je_editor/pyside_ui/git_ui/code_diff_compare/multi_file_diff_viewer.py +88 -0
  39. je_editor/pyside_ui/git_ui/code_diff_compare/side_by_side_diff_widget.py +284 -0
  40. je_editor/pyside_ui/git_ui/git_client/__init__.py +0 -0
  41. je_editor/pyside_ui/git_ui/git_client/commit_table.py +65 -0
  42. je_editor/pyside_ui/git_ui/git_client/git_branch_tree_widget.py +156 -0
  43. je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +799 -0
  44. je_editor/pyside_ui/git_ui/git_client/graph_view.py +218 -0
  45. je_editor/pyside_ui/main_ui/ai_widget/__init__.py +0 -0
  46. je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +34 -0
  47. je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +36 -0
  48. je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +147 -0
  49. je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +84 -0
  50. je_editor/pyside_ui/main_ui/console_widget/__init__.py +0 -0
  51. je_editor/pyside_ui/main_ui/console_widget/console_gui.py +162 -0
  52. je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +84 -0
  53. je_editor/pyside_ui/main_ui/dock/destroy_dock.py +32 -1
  54. je_editor/pyside_ui/main_ui/editor/editor_widget.py +113 -23
  55. je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +33 -6
  56. je_editor/pyside_ui/main_ui/editor/process_input.py +42 -10
  57. je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +45 -10
  58. je_editor/pyside_ui/main_ui/main_editor.py +189 -49
  59. je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +50 -27
  60. je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +141 -30
  61. je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +67 -17
  62. je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +33 -3
  63. je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +39 -0
  64. je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +102 -40
  65. je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +53 -6
  66. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +47 -3
  67. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +45 -5
  68. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +41 -3
  69. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +21 -0
  70. je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +37 -11
  71. je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +42 -6
  72. je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +202 -27
  73. je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +66 -0
  74. je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +18 -1
  75. je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +32 -2
  76. je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +37 -10
  77. je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +39 -0
  78. je_editor/start_editor.py +25 -0
  79. je_editor/utils/encodings/python_encodings.py +100 -97
  80. je_editor/utils/exception/exception_tags.py +11 -11
  81. je_editor/utils/file/open/open_file.py +35 -19
  82. je_editor/utils/file/save/save_file.py +34 -13
  83. je_editor/utils/json/json_file.py +29 -14
  84. je_editor/utils/json_format/json_process.py +32 -1
  85. je_editor/utils/logging/loggin_instance.py +37 -7
  86. je_editor/utils/multi_language/english.py +102 -6
  87. je_editor/utils/multi_language/multi_language_wrapper.py +28 -3
  88. je_editor/utils/multi_language/traditional_chinese.py +101 -10
  89. je_editor/utils/redirect_manager/redirect_manager_class.py +49 -11
  90. je_editor/utils/venv_check/check_venv.py +37 -14
  91. {je_editor-0.0.202.dist-info → je_editor-0.0.228.dist-info}/METADATA +12 -6
  92. je_editor-0.0.228.dist-info/RECORD +140 -0
  93. {je_editor-0.0.202.dist-info → je_editor-0.0.228.dist-info}/WHEEL +1 -1
  94. je_editor-0.0.202.dist-info/RECORD +0 -108
  95. {je_editor-0.0.202.dist-info → je_editor-0.0.228.dist-info/licenses}/LICENSE +0 -0
  96. {je_editor-0.0.202.dist-info → je_editor-0.0.228.dist-info}/top_level.txt +0 -0
@@ -1,15 +1,17 @@
1
- from __future__ import annotations
1
+ from __future__ import annotations # 支援延遲型別註解 (Python 3.7+)
2
2
 
3
- import queue
4
- import subprocess
5
- import sys
6
- from pathlib import Path
7
- from threading import Thread
8
- from typing import Union
3
+ import queue # 佇列,用於執行緒間傳遞訊息
4
+ import subprocess # 建立與管理子程序 (執行外部程式)
5
+ import sys # 系統相關資訊 (平台、參數等)
6
+ from pathlib import Path # 處理檔案與路徑
7
+ from threading import Thread # 執行緒,用於非同步處理
8
+ from typing import Union # 型別提示:允許多種型別
9
9
 
10
- from PySide6.QtCore import QTimer
11
- from PySide6.QtWidgets import QTextEdit
10
+ from PySide6.QtCore import QTimer # Qt 計時器,用於定時觸發事件
11
+ from PySide6.QtGui import QTextCharFormat # 設定文字格式 (顏色、字型等)
12
+ from PySide6.QtWidgets import QTextEdit # 文字編輯器元件
12
13
 
14
+ # 專案內部模組
13
15
  from je_editor.pyside_ui.code.running_process_manager import run_instance_manager
14
16
  from je_editor.pyside_ui.main_ui.editor.editor_widget import EditorWidget
15
17
  from je_editor.pyside_ui.main_ui.save_settings.user_color_setting_file import actually_color_dict
@@ -19,45 +21,59 @@ from je_editor.utils.logging.loggin_instance import jeditor_logger
19
21
  from je_editor.utils.venv_check.check_venv import check_and_choose_venv
20
22
 
21
23
 
24
+ # Support postponed evaluation of type annotations
25
+
26
+
22
27
  class ExecManager(object):
28
+ """
29
+ 程式執行管理器
30
+ Execution manager for running code inside the editor.
31
+ 負責:
32
+ - 建立子程序 (subprocess)
33
+ - 讀取標準輸出與錯誤輸出
34
+ - 將結果顯示在 QTextEdit
35
+ - 管理計時器與執行緒
36
+ """
23
37
 
24
38
  def __init__(
25
39
  self,
26
- main_window: Union[EditorWidget, None] = None,
27
- program_language: str = "python",
28
- program_encoding: str = "utf-8",
29
- program_buffer: int = 1024,
40
+ main_window: Union[EditorWidget, None] = None, # 主視窗 (可為 None)
41
+ program_language: str = "python", # 預設程式語言
42
+ program_encoding: str = "utf-8", # 預設編碼
43
+ program_buffer: int = 1024, # 緩衝區大小
30
44
  ):
31
45
  """
32
- :param main_window: Pyside main window
33
- :param program_language: which program language
34
- :param program_encoding: which encoding
46
+ 初始化執行管理器
47
+ Initialize ExecManager
35
48
  """
36
49
  jeditor_logger.info(f"Init ExecManager "
37
50
  f"main_window: {main_window} "
38
51
  f"program_language: {program_language} "
39
52
  f"program_encoding: {program_encoding} "
40
53
  f"program_buffer: {program_buffer}")
41
- self.read_program_error_output_from_thread = None
42
- self.read_program_output_from_thread = None
43
- self.main_window: EditorWidget = main_window
44
- self.compiler_path = None
45
- self.code_result: Union[QTextEdit, None] = None
46
- self.timer: Union[QTimer, None] = None
47
- self.still_run_program = True
48
- self.process: Union[subprocess.Popen, None] = None
49
- self.run_output_queue = queue.Queue()
50
- self.run_error_queue = queue.Queue()
54
+ # 初始化屬性
55
+ self.read_program_error_output_from_thread = None # 錯誤輸出讀取執行緒
56
+ self.read_program_output_from_thread = None # 標準輸出讀取執行緒
57
+ self.main_window: EditorWidget = main_window # 主視窗
58
+ self.compiler_path = None # 編譯器/直譯器路徑
59
+ self.code_result: Union[QTextEdit, None] = None # 顯示程式輸出的文字框
60
+ self.code_result_cursor: Union[QTextEdit.textCursor, None] = None
61
+ self.timer: Union[QTimer, None] = None # 定時器
62
+ self.still_run_program = True # 程式是否仍在執行
63
+ self.process: Union[subprocess.Popen, None] = None # 子程序
64
+ self.run_output_queue = queue.Queue() # 標準輸出佇列
65
+ self.run_error_queue = queue.Queue() # 錯誤輸出佇列
51
66
  self.program_language = program_language
52
67
  self.program_encoding = program_encoding
53
68
  self.program_buffer = program_buffer
54
- self.renew_path()
55
- run_instance_manager.instance_list.append(self)
69
+ self.renew_path() # 設定 Python 直譯器路徑
70
+ run_instance_manager.instance_list.append(self) # 註冊到全域執行管理器
56
71
 
57
72
  def renew_path(self) -> None:
73
+ """更新 Python 直譯器路徑 / Renew compiler path"""
58
74
  jeditor_logger.info("ExecManager renew_path")
59
75
  if self.main_window.python_compiler is None:
60
- # Renew compiler path
76
+ # 如果主視窗沒有指定 Python,則使用虛擬環境
61
77
  if sys.platform in ["win32", "cygwin", "msys"]:
62
78
  venv_path = Path(str(Path.cwd()) + "/venv/Scripts")
63
79
  else:
@@ -67,8 +83,8 @@ class ExecManager(object):
67
83
  self.compiler_path = self.main_window.python_compiler
68
84
 
69
85
  def later_init(self) -> None:
86
+ """延遲初始化,設定輸出區與計時器 / Setup code result area and timer"""
70
87
  jeditor_logger.info("ExecManager later_init")
71
- # Enable timer and code result area
72
88
  if self.main_window is not None:
73
89
  self.code_result: QTextEdit = self.main_window.code_result
74
90
  self.timer = QTimer(self.main_window)
@@ -77,71 +93,83 @@ class ExecManager(object):
77
93
 
78
94
  def exec_code(self, exec_file_name, exec_prefix: Union[str, list] = None) -> None:
79
95
  """
80
- :param exec_file_name: string file will open to run
81
- :param exec_prefix: user define exec prefix
82
- :return: if error return result and True else return result and False
96
+ 執行指定檔案
97
+ Execute given file
98
+ :param exec_file_name: 要執行的檔案名稱
99
+ :param exec_prefix: 使用者自定義前綴 (例如 python -m)
83
100
  """
84
101
  jeditor_logger.info(f"ExecManager exec_code "
85
102
  f"exec_file_name: {exec_file_name} "
86
103
  f"exec_prefix: {exec_prefix}")
87
104
  try:
88
- self.exit_program()
89
- self.code_result.setTextColor(actually_color_dict.get("normal_output_color"))
90
- self.code_result.setPlainText("")
105
+ self.exit_program() # 確保先結束舊的程式
106
+ self.code_result.setPlainText("") # 清空輸出區
91
107
  file_path = Path(exec_file_name)
92
108
  reformat_os_file_path = str(file_path.absolute())
93
- # detect file is exist
94
109
  exec_file = reformat_os_file_path
95
- # run program
110
+
111
+ # 建立執行參數
96
112
  if exec_prefix is None:
97
113
  execute_program_param = [self.compiler_path, exec_file]
98
114
  else:
99
115
  if isinstance(exec_prefix, str):
100
116
  execute_program_param = [self.compiler_path, exec_prefix, exec_file]
101
117
  else:
102
- execute_program_param = list()
103
- execute_program_param.append(self.compiler_path)
104
- for prefix in exec_prefix:
105
- execute_program_param.append(prefix)
106
- execute_program_param.append(exec_file)
118
+ execute_program_param = [self.compiler_path] + exec_prefix + [exec_file]
119
+
120
+ # Windows 平台需轉為字串
107
121
  if sys.platform not in ["win32", "cygwin", "msys"]:
108
122
  execute_program_param = " ".join(execute_program_param)
123
+
124
+ # 建立子程序
109
125
  self.process = subprocess.Popen(
110
126
  execute_program_param,
111
127
  stdout=subprocess.PIPE,
112
128
  stderr=subprocess.PIPE,
113
129
  stdin=subprocess.PIPE,
114
- shell=True
130
+ shell=False
115
131
  )
116
132
  self.still_run_program = True
117
- # program output message queue thread
133
+
134
+ # 啟動輸出讀取執行緒
118
135
  self.read_program_output_from_thread = Thread(
119
136
  target=self.read_program_output_from_process,
120
137
  daemon=True
121
138
  )
122
139
  self.read_program_output_from_thread.start()
123
- # program error message queue thread
140
+
141
+ # 啟動錯誤讀取執行緒
124
142
  self.read_program_error_output_from_thread = Thread(
125
143
  target=self.read_program_error_output_from_process,
126
144
  daemon=True
127
145
  )
128
146
  self.read_program_error_output_from_thread.start()
129
- # show which file execute
130
- self.code_result.append(self.compiler_path + " " + reformat_os_file_path)
131
- # start tkinter_ui update
132
- # start timer
147
+
148
+ # 顯示執行的檔案路徑
149
+ text_cursor = self.code_result.textCursor()
150
+ text_format = QTextCharFormat()
151
+ text_format.setForeground(actually_color_dict.get("normal_output_color"))
152
+ text_cursor.insertText(self.compiler_path + " " + reformat_os_file_path, text_format)
153
+ text_cursor.insertBlock()
154
+
155
+ # 啟動定時器,每 10ms 更新輸出
133
156
  self.timer = QTimer(self.main_window)
134
157
  self.timer.setInterval(10)
135
158
  self.timer.timeout.connect(self.pull_text)
136
159
  self.timer.start()
160
+
137
161
  except Exception as error:
138
- self.code_result.setTextColor(actually_color_dict.get("error_output_color"))
139
- self.code_result.append(str(error))
140
- self.code_result.setTextColor(actually_color_dict.get("normal_output_color"))
162
+ # 發生錯誤時顯示錯誤訊息
163
+ text_cursor = self.code_result.textCursor()
164
+ text_format = QTextCharFormat()
165
+ text_format.setForeground(actually_color_dict.get("normal_output_color"))
166
+ text_cursor.insertText(str(error), text_format)
167
+ text_cursor.insertBlock()
141
168
  if self.process is not None:
142
169
  self.process.terminate()
143
170
 
144
171
  def full_exit_program(self):
172
+ """完全結束程式 / Fully exit program"""
145
173
  jeditor_logger.info("ExecManager full_exit_program")
146
174
  self.timer.stop()
147
175
  self.exit_program()
@@ -149,64 +177,90 @@ class ExecManager(object):
149
177
 
150
178
  def pull_text(self) -> None:
151
179
  jeditor_logger.info("ExecManager pull_text")
180
+ # 從佇列中取出訊息並顯示到 QTextEdit
152
181
  # Pull text from queue and put in code result area
153
182
  try:
154
- self.code_result.setTextColor(actually_color_dict.get("normal_output_color"))
183
+ # 處理標準輸出
155
184
  if not self.run_output_queue.empty():
156
185
  output_message = self.run_output_queue.get_nowait()
157
186
  output_message = str(output_message).strip()
158
187
  if output_message:
159
- self.code_result.append(output_message)
160
- self.code_result.setTextColor(actually_color_dict.get("error_output_color"))
188
+ text_cursor = self.code_result.textCursor()
189
+ text_format = QTextCharFormat()
190
+ text_format.setForeground(actually_color_dict.get("normal_output_color"))
191
+ text_cursor.insertText(output_message, text_format)
192
+ text_cursor.insertBlock()
193
+ # 處理錯誤輸出
161
194
  if not self.run_error_queue.empty():
162
195
  error_message = self.run_error_queue.get_nowait()
163
196
  error_message = str(error_message).strip()
164
197
  if error_message:
165
- self.code_result.append(error_message)
166
- self.code_result.setTextColor(actually_color_dict.get("normal_output_color"))
198
+ text_cursor = self.code_result.textCursor()
199
+ text_format = QTextCharFormat()
200
+ text_format.setForeground(actually_color_dict.get("error_output_color"))
201
+ text_cursor.insertText(error_message, text_format)
202
+ text_cursor.insertBlock()
167
203
  except queue.Empty:
204
+ # 如果佇列是空的就忽略
168
205
  pass
206
+
207
+ # 如果子程序已經結束(returncode 不為 None),則完全退出
169
208
  if self.process.returncode == 0:
170
209
  self.full_exit_program()
171
210
  elif self.process.returncode is not None:
172
211
  self.full_exit_program()
212
+
213
+ # 如果程式仍在執行,持續檢查狀態
173
214
  if self.still_run_program:
174
- # poll return code
215
+ # poll() 不會阻塞,只是更新 returncode
175
216
  self.process.poll()
176
217
 
177
- # Exit program change run flag to false and clean read thread and queue and process
218
+ # 結束程式:將執行旗標設為 False,清理執行緒、佇列與子程序
219
+ # Exit program: change run flag to false and clean read thread, queue, and process
178
220
  def exit_program(self) -> None:
179
221
  jeditor_logger.info("ExecManager exit_program")
180
222
  self.still_run_program = False
223
+ # 清除讀取執行緒的引用
181
224
  if self.read_program_output_from_thread is not None:
182
225
  self.read_program_output_from_thread = None
183
226
  if self.read_program_error_output_from_thread is not None:
184
227
  self.read_program_error_output_from_thread = None
228
+ # 清空佇列
185
229
  self.print_and_clear_queue()
230
+ # 如果子程序存在,則終止
186
231
  if self.process is not None:
187
232
  self.process.terminate()
188
- self.code_result.append(f"Program exit with code {self.process.returncode}")
233
+ text_cursor = self.code_result.textCursor()
234
+ text_format = QTextCharFormat()
235
+ text_format.setForeground(actually_color_dict.get("normal_output_color"))
236
+ text_cursor.insertText(f"Program exit with code {self.process.returncode}", text_format)
237
+ text_cursor.insertBlock()
189
238
  self.process = None
190
239
 
191
- # Pull all remain string on queue and add to code result area
240
+ # 清空輸出與錯誤佇列
241
+ # Pull all remaining strings in queues and reset them
192
242
  def print_and_clear_queue(self) -> None:
193
243
  jeditor_logger.info("ExecManager print_and_clear_queue")
194
244
  self.run_output_queue = queue.Queue()
195
245
  self.run_error_queue = queue.Queue()
196
246
 
247
+ # 從子程序 stdout 持續讀取資料並放入輸出佇列
248
+ # Continuously read from process stdout and put into output queue
197
249
  def read_program_output_from_process(self) -> None:
198
250
  jeditor_logger.info("ExecManager read_program_output_from_process")
199
251
  while self.still_run_program:
200
- program_output_data: str = self.process.stdout.read(
252
+ program_output_data: str = self.process.stdout.readline(
201
253
  self.program_buffer).decode(self.program_encoding, "replace")
202
254
  if self.process:
203
255
  self.process.stdout.flush()
204
256
  self.run_output_queue.put_nowait(program_output_data)
205
257
 
258
+ # 從子程序 stderr 持續讀取資料並放入錯誤佇列
259
+ # Continuously read from process stderr and put into error queue
206
260
  def read_program_error_output_from_process(self) -> None:
207
261
  jeditor_logger.info("ExecManager read_program_error_output_from_process")
208
262
  while self.still_run_program:
209
- program_error_output_data: str = self.process.stderr.read(
263
+ program_error_output_data: str = self.process.stderr.readline(
210
264
  self.program_buffer).decode(self.program_encoding, "replace")
211
265
  if self.process:
212
266
  self.process.stderr.flush()