je-editor 0.0.222__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 (75) hide show
  1. je_editor/__init__.py +2 -2
  2. je_editor/git_client/commit_graph.py +7 -7
  3. je_editor/git_client/git_action.py +0 -7
  4. je_editor/pyside_ui/browser/browser_view.py +16 -4
  5. je_editor/pyside_ui/browser/browser_widget.py +43 -29
  6. je_editor/pyside_ui/browser/main_browser_widget.py +85 -0
  7. je_editor/pyside_ui/code/auto_save/auto_save_manager.py +34 -2
  8. je_editor/pyside_ui/code/auto_save/auto_save_thread.py +19 -6
  9. je_editor/pyside_ui/code/code_format/pep8_format.py +53 -9
  10. je_editor/pyside_ui/code/code_process/code_exec.py +88 -52
  11. je_editor/pyside_ui/code/plaintext_code_edit/code_edit_plaintext.py +116 -55
  12. je_editor/pyside_ui/code/running_process_manager.py +19 -1
  13. je_editor/pyside_ui/code/shell_process/shell_exec.py +71 -48
  14. je_editor/pyside_ui/code/syntax/python_syntax.py +45 -10
  15. je_editor/pyside_ui/code/syntax/syntax_setting.py +40 -12
  16. je_editor/pyside_ui/code/textedit_code_result/code_record.py +34 -12
  17. je_editor/pyside_ui/code/variable_inspector/inspector_gui.py +53 -6
  18. je_editor/pyside_ui/dialog/ai_dialog/set_ai_dialog.py +30 -3
  19. je_editor/pyside_ui/dialog/file_dialog/create_file_dialog.py +35 -2
  20. je_editor/pyside_ui/dialog/file_dialog/open_file_dialog.py +33 -5
  21. je_editor/pyside_ui/dialog/file_dialog/save_file_dialog.py +25 -3
  22. je_editor/pyside_ui/dialog/search_ui/search_error_box.py +26 -1
  23. je_editor/pyside_ui/dialog/search_ui/search_text_box.py +26 -1
  24. je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +11 -11
  25. je_editor/pyside_ui/git_ui/git_client/commit_table.py +46 -8
  26. je_editor/pyside_ui/git_ui/git_client/git_branch_tree_widget.py +49 -15
  27. je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +81 -16
  28. je_editor/pyside_ui/git_ui/git_client/graph_view.py +64 -20
  29. je_editor/pyside_ui/main_ui/ai_widget/ai_config.py +20 -5
  30. je_editor/pyside_ui/main_ui/ai_widget/ask_thread.py +20 -1
  31. je_editor/pyside_ui/main_ui/ai_widget/chat_ui.py +56 -41
  32. je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +45 -6
  33. je_editor/pyside_ui/main_ui/console_widget/console_gui.py +44 -12
  34. je_editor/pyside_ui/main_ui/console_widget/qprocess_adapter.py +34 -13
  35. je_editor/pyside_ui/main_ui/dock/destroy_dock.py +33 -2
  36. je_editor/pyside_ui/main_ui/editor/editor_widget.py +104 -20
  37. je_editor/pyside_ui/main_ui/editor/editor_widget_dock.py +34 -7
  38. je_editor/pyside_ui/main_ui/editor/process_input.py +38 -11
  39. je_editor/pyside_ui/main_ui/ipython_widget/rich_jupyter.py +46 -11
  40. je_editor/pyside_ui/main_ui/main_editor.py +180 -42
  41. je_editor/pyside_ui/main_ui/menu/check_style_menu/build_check_style_menu.py +51 -28
  42. je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +83 -36
  43. je_editor/pyside_ui/main_ui/menu/file_menu/build_file_menu.py +70 -17
  44. je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +35 -4
  45. je_editor/pyside_ui/main_ui/menu/language_menu/build_language_server.py +41 -1
  46. je_editor/pyside_ui/main_ui/menu/python_env_menu/build_venv_menu.py +100 -42
  47. je_editor/pyside_ui/main_ui/menu/run_menu/build_run_menu.py +57 -7
  48. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_debug_menu.py +50 -4
  49. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_program_menu.py +52 -6
  50. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/build_shell_menu.py +44 -4
  51. je_editor/pyside_ui/main_ui/menu/run_menu/under_run_menu/utils.py +23 -1
  52. je_editor/pyside_ui/main_ui/menu/set_menu_bar.py +37 -12
  53. je_editor/pyside_ui/main_ui/menu/style_menu/build_style_menu.py +44 -7
  54. je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +127 -44
  55. je_editor/pyside_ui/main_ui/menu/text_menu/build_text_menu.py +65 -1
  56. je_editor/pyside_ui/main_ui/save_settings/setting_utils.py +18 -1
  57. je_editor/pyside_ui/main_ui/save_settings/user_color_setting_file.py +33 -3
  58. je_editor/pyside_ui/main_ui/save_settings/user_setting_file.py +38 -11
  59. je_editor/pyside_ui/main_ui/system_tray/extend_system_tray.py +39 -2
  60. je_editor/start_editor.py +26 -1
  61. je_editor/utils/encodings/python_encodings.py +101 -98
  62. je_editor/utils/file/open/open_file.py +36 -19
  63. je_editor/utils/file/save/save_file.py +35 -14
  64. je_editor/utils/json/json_file.py +29 -14
  65. je_editor/utils/json_format/json_process.py +33 -2
  66. je_editor/utils/logging/loggin_instance.py +38 -8
  67. je_editor/utils/multi_language/multi_language_wrapper.py +29 -4
  68. je_editor/utils/redirect_manager/redirect_manager_class.py +49 -11
  69. je_editor/utils/venv_check/check_venv.py +45 -15
  70. {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/METADATA +1 -1
  71. {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/RECORD +74 -74
  72. je_editor/git_client/github.py +0 -81
  73. {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/WHEEL +0 -0
  74. {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/licenses/LICENSE +0 -0
  75. {je_editor-0.0.222.dist-info → je_editor-0.0.224.dist-info}/top_level.txt +0 -0
@@ -7,12 +7,23 @@ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapp
7
7
 
8
8
 
9
9
  class VariableModel(QAbstractTableModel):
10
+ """
11
+ 變數模型:負責管理與顯示 Python 全域變數
12
+ Variable model: manages and displays Python global variables
13
+ """
10
14
  def __init__(self, parent=None):
11
15
  super().__init__(parent)
12
- self.variables = []
16
+ self.variables = [] # 儲存變數資訊 [名稱, 型別, 值字串, 真實值]
17
+ # Store variable info [name, type, repr(value), actual value]
13
18
 
14
19
  def update_data(self):
20
+ """
21
+ 更新變數清單,從全域變數中擷取
22
+ Update variable list from globals()
23
+ """
15
24
  parent_widget = self.parent()
25
+ # 避免在 table 正在互動時更新,造成衝突
26
+ # Avoid updating while table is in active state
16
27
  if parent_widget and getattr(parent_widget, "table", None):
17
28
  if parent_widget.table.state() != QTableView.State.NoState:
18
29
  return
@@ -22,17 +33,21 @@ class VariableModel(QAbstractTableModel):
22
33
  self.variables = [
23
34
  [name, type(value).__name__, repr(value), value]
24
35
  for name, value in vars_dict.items()
25
- if not name.startswith("__") # 過濾內建變數
36
+ if not name.startswith("__") # 過濾內建變數 / filter out built-in variables
26
37
  ]
27
38
  self.endResetModel()
28
39
 
29
40
  def rowCount(self, parent=None):
41
+ # 回傳變數數量 / return number of variables
30
42
  return len(self.variables)
31
43
 
32
44
  def columnCount(self, parent=None):
45
+ # 固定三欄:名稱、型別、值 / fixed 3 columns: name, type, value
33
46
  return 3
34
47
 
35
48
  def data(self, index, role=Qt.ItemDataRole.DisplayRole):
49
+ # 提供表格顯示的資料
50
+ # Provide data for table display
36
51
  if not index.isValid() or not (0 <= index.row() < len(self.variables)):
37
52
  return None
38
53
  if role == Qt.ItemDataRole.DisplayRole:
@@ -40,6 +55,8 @@ class VariableModel(QAbstractTableModel):
40
55
  return None
41
56
 
42
57
  def headerData(self, section, orientation, role=Qt.ItemDataRole.DisplayRole):
58
+ # 設定表頭文字 (支援多語系)
59
+ # Set header labels (multi-language support)
43
60
  if role == Qt.ItemDataRole.DisplayRole and orientation == Qt.Orientation.Horizontal:
44
61
  return [
45
62
  language_wrapper.language_word_dict.get("variable_inspector_var_name"),
@@ -49,14 +66,20 @@ class VariableModel(QAbstractTableModel):
49
66
  return None
50
67
 
51
68
  def flags(self, index):
69
+ # 設定欄位屬性,僅允許「值」欄可編輯
70
+ # Set column flags, only "value" column is editable
52
71
  if not index.isValid() or not (0 <= index.row() < len(self.variables)):
53
72
  return Qt.ItemFlag.NoItemFlags
54
73
  base = super().flags(index)
55
- if index.column() == 2: # 只允許編輯值欄
74
+ if index.column() == 2: # 只允許編輯值欄 / only value column editable
56
75
  base |= Qt.ItemFlag.ItemIsEditable
57
76
  return base
58
77
 
59
78
  def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
79
+ """
80
+ 更新變數值,並同步到全域變數
81
+ Update variable value and sync to globals()
82
+ """
60
83
  if role == Qt.ItemDataRole.EditRole and index.column() == 2:
61
84
 
62
85
  if value == "":
@@ -68,13 +91,19 @@ class VariableModel(QAbstractTableModel):
68
91
 
69
92
  var_name = self.variables[index.row()][0]
70
93
  try:
94
+ # 嘗試將輸入轉換為 Python 物件
95
+ # Try to evaluate input as Python object
71
96
  new_value = ast.literal_eval(value)
72
97
  except Exception:
98
+ # 若失敗則當作字串處理
99
+ # If failed, treat as string
73
100
  new_value = value
74
101
 
75
102
  if new_value == self.variables[index.row()][3]:
76
103
  return False
77
104
 
105
+ # 更新全域變數與模型資料
106
+ # Update globals and model data
78
107
  globals()[var_name] = new_value
79
108
  self.variables[index.row()][2] = repr(new_value)
80
109
  self.variables[index.row()][3] = new_value
@@ -82,29 +111,44 @@ class VariableModel(QAbstractTableModel):
82
111
  return True
83
112
  return False
84
113
 
114
+
85
115
  class VariableProxy(QSortFilterProxyModel):
116
+ """
117
+ 過濾代理模型:支援搜尋與編輯轉發
118
+ Proxy model: supports filtering and forwards editing
119
+ """
86
120
  def setData(self, index, value, role=Qt.ItemDataRole.EditRole):
121
+ # 將編輯操作轉發到原始模型
122
+ # Forward editing to source model
87
123
  return self.sourceModel().setData(
88
124
  self.mapToSource(index), value, role
89
125
  )
90
126
 
127
+
91
128
  class VariableInspector(QWidget):
129
+ """
130
+ 變數檢視器:提供 GUI 介面顯示與搜尋全域變數
131
+ Variable inspector: GUI interface to display and search global variables
132
+ """
92
133
  def __init__(self):
93
134
  super().__init__()
94
135
  self.setWindowTitle(language_wrapper.language_word_dict.get("variable_inspector_title"))
95
136
  layout = QVBoxLayout(self)
96
137
 
138
+ # 搜尋框 / search box
97
139
  self.search_box = QLineEdit()
98
140
  self.search_box.setPlaceholderText(language_wrapper.language_word_dict.get("variable_inspector_search"))
99
141
  layout.addWidget(QLabel(language_wrapper.language_word_dict.get("variable_inspector_search")))
100
142
  layout.addWidget(self.search_box)
101
143
 
144
+ # 模型與代理模型 / model and proxy model
102
145
  self.model = VariableModel(parent=self)
103
146
  self.proxy_model = VariableProxy(self)
104
147
  self.proxy_model.setSourceModel(self.model)
105
- self.proxy_model.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive)
106
- self.proxy_model.setFilterKeyColumn(0)
148
+ self.proxy_model.setFilterCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive) # 不分大小寫 / case-insensitive
149
+ self.proxy_model.setFilterKeyColumn(0) # 僅針對變數名稱過濾 / filter by variable name
107
150
 
151
+ # 表格顯示 / table view
108
152
  self.table = QTableView()
109
153
  self.table.setModel(self.proxy_model)
110
154
  self.table.horizontalHeader().setStretchLastSection(True)
@@ -113,10 +157,13 @@ class VariableInspector(QWidget):
113
157
  )
114
158
  layout.addWidget(self.table, stretch=1)
115
159
 
160
+ # 綁定搜尋框輸入事件 / bind search box input
116
161
  self.search_box.textChanged.connect(
117
162
  self.proxy_model.setFilterFixedString
118
163
  )
119
164
 
165
+ # 定時更新變數清單 (每 500ms)
166
+ # Periodically update variable list (every 500ms)
120
167
  self.timer = QTimer(self)
121
168
  self.timer.timeout.connect(self.model.update_data)
122
- self.timer.start(500)
169
+ self.timer.start(500)
@@ -6,19 +6,33 @@ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapp
6
6
 
7
7
 
8
8
  class SetAIDialog(QWidget):
9
+ """
10
+ 設定 AI 模型的對話框
11
+ Dialog for configuring AI model settings
12
+ """
9
13
 
10
14
  def __init__(self):
11
15
  jeditor_logger.info("Init SetAIDialog")
12
16
  super().__init__()
17
+
18
+ # Base URL 輸入欄位 / Base URL input field
13
19
  self.base_url_label = QLabel(language_wrapper.language_word_dict.get("base_url_label"))
14
20
  self.base_url_input = QLineEdit()
21
+
22
+ # API Key 輸入欄位 / API Key input field
15
23
  self.api_key_label = QLabel(language_wrapper.language_word_dict.get("api_key_label"))
16
24
  self.api_key_input = QLineEdit()
25
+
26
+ # Chat Model 輸入欄位 / Chat model input field
17
27
  self.chat_model_label = QLabel(language_wrapper.language_word_dict.get("ai_model_label"))
18
28
  self.chat_model_input = QLineEdit()
29
+
30
+ # 新增 AI 設定按鈕 / Button to add AI configuration
19
31
  self.add_ai_info_button = QPushButton()
20
32
  self.add_ai_info_button.setText(language_wrapper.language_word_dict.get("add_ai_model_pushbutton"))
21
33
  self.add_ai_info_button.clicked.connect(self.update_ai_config)
34
+
35
+ # 使用 GridLayout 排版 / Use GridLayout for layout
22
36
  self.grid_layout = QGridLayout()
23
37
  self.grid_layout.addWidget(self.base_url_label, 0, 0)
24
38
  self.grid_layout.addWidget(self.base_url_input, 0, 1)
@@ -27,18 +41,31 @@ class SetAIDialog(QWidget):
27
41
  self.grid_layout.addWidget(self.chat_model_label, 2, 0)
28
42
  self.grid_layout.addWidget(self.chat_model_input, 2, 1)
29
43
  self.grid_layout.addWidget(self.add_ai_info_button, 3, 1)
44
+
45
+ # 設定視窗標題 / Set window title
30
46
  self.setWindowTitle(language_wrapper.language_word_dict.get("add_ai_model_title"))
31
47
  self.setLayout(self.grid_layout)
32
48
 
33
49
  def update_ai_config(self):
50
+ """
51
+ 更新 AI 設定,將使用者輸入的 base_url、api_key、chat_model
52
+ 儲存到 ai_config.choosable_ai 中
53
+ Update AI configuration with user inputs (base_url, api_key, chat_model)
54
+ """
34
55
  base_url = self.base_url_input.text().strip()
35
56
  api_key = self.api_key_input.text().strip()
36
57
  chat_model = self.chat_model_input.text().strip()
58
+
37
59
  if base_url and chat_model:
60
+ # 更新設定字典 / Update configuration dictionary
38
61
  ai_config.choosable_ai.update(
39
62
  {"AI_model": {"base_url": base_url, "api_key": api_key, "chat_model": chat_model}}
40
63
  )
41
64
  else:
42
- QMessageBox.warning(self,
43
- language_wrapper.language_word_dict.get("set_ai_model_warring_title"),
44
- language_wrapper.language_word_dict.get("set_ai_model_warring_text"))
65
+ # 若缺少必要欄位,顯示警告訊息框
66
+ # Show warning message box if required fields are missing
67
+ QMessageBox.warning(
68
+ self,
69
+ language_wrapper.language_word_dict.get("set_ai_model_warring_title"),
70
+ language_wrapper.language_word_dict.get("set_ai_model_warring_text")
71
+ )
@@ -5,31 +5,64 @@ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapp
5
5
 
6
6
 
7
7
  class CreateFileDialog(QWidget):
8
+ """
9
+ 建立新檔案的對話框
10
+ Dialog for creating a new file
11
+ """
8
12
 
9
13
  def __init__(self):
10
14
  jeditor_logger.info("Init CreateFileDialog")
11
15
  super().__init__()
16
+
17
+ # 垂直佈局 (上到下)
18
+ # Vertical layout (top to bottom)
12
19
  self.box_layout = QBoxLayout(QBoxLayout.Direction.TopToBottom)
20
+
21
+ # 檔案名稱輸入框 / File name input field
13
22
  self.file_name_input = QLineEdit()
23
+
24
+ # 建立檔案按鈕 / Create file button
14
25
  self.create_file_button = QPushButton()
15
26
  self.create_file_button.setText(language_wrapper.language_word_dict.get("create_file_dialog_pushbutton"))
16
27
  self.create_file_button.clicked.connect(self.create_file)
28
+
29
+ # 水平佈局 (放置按鈕) / Horizontal layout (for button)
17
30
  self.box_h_layout = QHBoxLayout()
18
31
  self.box_h_layout.addWidget(self.create_file_button)
32
+
33
+ # 將元件加入主佈局 / Add widgets to main layout
19
34
  self.box_layout.addWidget(self.file_name_input)
20
35
  self.box_layout.addLayout(self.box_h_layout)
36
+
37
+ # 設定視窗標題 / Set window title
21
38
  self.setWindowTitle(language_wrapper.language_word_dict.get("create_file_dialog_pushbutton"))
22
39
  self.setLayout(self.box_layout)
23
40
 
24
41
  def create_file(self):
42
+ """
43
+ 建立檔案的邏輯:
44
+ 1. 檢查輸入是否為空
45
+ 2. 若為空,顯示警告訊息
46
+ 3. 否則建立新檔案並關閉對話框
47
+ File creation logic:
48
+ 1. Check if input is empty
49
+ 2. If empty, show warning message
50
+ 3. Otherwise, create new file and close dialog
51
+ """
25
52
  jeditor_logger.info("CreateFileDialog create_file")
26
53
  file_name = self.file_name_input.text().strip()
54
+
27
55
  if file_name == "":
56
+ # 若未輸入檔名,顯示提示訊息
57
+ # Show warning if no file name is entered
28
58
  create_file_message_box = QMessageBox(self)
29
59
  create_file_message_box.setText(
30
- language_wrapper.language_word_dict.get("input_file_name_dialog_pushbutton"))
60
+ language_wrapper.language_word_dict.get("input_file_name_dialog_pushbutton")
61
+ )
31
62
  create_file_message_box.show()
32
63
  else:
64
+ # 建立新檔案 (若存在則覆蓋)
65
+ # Create new file (overwrite if exists)
33
66
  with open(file_name, "w+") as file:
34
67
  file.write("")
35
- self.close()
68
+ self.close() # 關閉對話框 / close dialog
@@ -12,6 +12,8 @@ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapp
12
12
  from je_editor.utils.venv_check.check_venv import check_and_choose_venv
13
13
 
14
14
  if TYPE_CHECKING:
15
+ # 僅在型別檢查時匯入,避免循環依賴
16
+ # Only imported during type checking to avoid circular imports
15
17
  from je_editor.pyside_ui.main_ui.main_editor import EditorMain
16
18
 
17
19
  from PySide6.QtWidgets import QFileDialog
@@ -22,14 +24,16 @@ from je_editor.utils.file.open.open_file import read_file
22
24
 
23
25
  def choose_file_get_open_file_path(parent_qt_instance: EditorMain) -> None:
24
26
  """
27
+ 開啟檔案並將內容載入編輯器
25
28
  Open file and set code edit content
26
- :param parent_qt_instance: Pyside parent
29
+ :param parent_qt_instance: Pyside 主視窗 / Pyside parent
27
30
  :return: None
28
31
  """
29
32
  jeditor_logger.info("open_file_dialog.py choose_file_get_open_file_path"
30
33
  f" parent_qt_instance: {parent_qt_instance}")
31
34
  widget = parent_qt_instance.tab_widget.currentWidget()
32
35
  if isinstance(widget, EditorWidget):
36
+ # 開啟檔案選擇對話框 / Open file dialog
33
37
  file_path = QFileDialog().getOpenFileName(
34
38
  parent=parent_qt_instance,
35
39
  dir=str(Path.cwd()),
@@ -37,27 +41,40 @@ def choose_file_get_open_file_path(parent_qt_instance: EditorMain) -> None:
37
41
  HTML file (*.html);;
38
42
  File (*.*)"""
39
43
  )[0]
44
+
40
45
  if file_path is not None and file_path != "":
46
+ # 檢查檔案是否已經開啟 / Check if file already opened
41
47
  if file_is_open_manager_dict.get(str(Path(file_path)), None) is not None:
42
48
  widget.tab_manager.setCurrentWidget(
43
49
  widget.tab_manager.findChild(EditorWidget, str(Path(file_path).name)))
44
50
  return
45
51
  else:
52
+ # 記錄已開啟檔案 / Register opened file
46
53
  file_is_open_manager_dict.update({file_path: str(Path(file_path).name)})
54
+
55
+ # 設定目前檔案路徑 / Set current file path
47
56
  widget.current_file = file_path
57
+ # 讀取檔案內容 / Read file content
48
58
  file_content = read_file(file_path)[1]
49
- widget.code_edit.setPlainText(
50
- file_content
51
- )
59
+ widget.code_edit.setPlainText(file_content)
60
+
61
+ # 啟動自動儲存執行緒 / Start auto-save thread
52
62
  if widget.current_file is not None and widget.code_save_thread is None:
53
63
  init_new_auto_save_thread(widget.current_file, widget)
54
64
  else:
55
65
  widget.code_save_thread.file = widget.current_file
66
+
67
+ # 更新使用者設定中的最後開啟檔案 / Update last opened file in user settings
56
68
  user_setting_dict.update({"last_file": str(widget.current_file)})
69
+ # 更新分頁標題 / Rename tab title
57
70
  widget.rename_self_tab()
58
71
 
59
72
 
60
73
  def choose_dir_get_dir_path(parent_qt_instance: EditorMain) -> None:
74
+ """
75
+ 選擇資料夾並更新工作目錄與專案樹
76
+ Choose directory and update working dir and project tree
77
+ """
61
78
  jeditor_logger.info("open_file_dialog.py choose_dir_get_dir_path"
62
79
  f" parent_qt_instance: {parent_qt_instance}")
63
80
  dir_path = QFileDialog().getExistingDirectory(parent=parent_qt_instance, )
@@ -65,19 +82,30 @@ def choose_dir_get_dir_path(parent_qt_instance: EditorMain) -> None:
65
82
  check_path = Path(dir_path)
66
83
  else:
67
84
  return
85
+
68
86
  if check_path.exists() and check_path.is_dir():
87
+ # 更新工作目錄 / Update working directory
69
88
  parent_qt_instance.working_dir = dir_path
70
89
  os.chdir(dir_path)
90
+
91
+ # 更新所有編輯器的專案樹與環境檢查 / Update project tree and check env for all editors
71
92
  for code_editor in range(parent_qt_instance.tab_widget.count()):
72
93
  widget = parent_qt_instance.tab_widget.widget(code_editor)
73
94
  if isinstance(widget, EditorWidget):
74
95
  widget.project_treeview.setRootIndex(widget.project_treeview_model.index(dir_path))
75
96
  widget.code_edit.check_env()
97
+
98
+ # 設定虛擬環境路徑 / Set virtual environment path
76
99
  if sys.platform in ["win32", "cygwin", "msys"]:
77
100
  venv_path = Path(os.getcwd() + "/venv/Scripts")
78
101
  else:
79
102
  venv_path = Path(os.getcwd() + "/venv/bin")
103
+
80
104
  parent_qt_instance.python_compiler = check_and_choose_venv(venv_path)
105
+
106
+ # 重新讀取使用者設定並套用啟動設定 / Reload user settings and apply startup settings
81
107
  read_user_setting()
82
108
  parent_qt_instance.startup_setting()
83
- language_wrapper.reset_language(user_setting_dict.get("language", "English"))
109
+
110
+ # 重設語言設定 / Reset language
111
+ language_wrapper.reset_language(user_setting_dict.get("language", "English"))
@@ -8,7 +8,10 @@ from je_editor.pyside_ui.code.auto_save.auto_save_manager import file_is_open_ma
8
8
  from je_editor.utils.logging.loggin_instance import jeditor_logger
9
9
 
10
10
  if TYPE_CHECKING:
11
+ # 僅在型別檢查時匯入,避免循環依賴
12
+ # Only imported during type checking to avoid circular imports
11
13
  from je_editor.pyside_ui.main_ui.main_editor import EditorMain
14
+
12
15
  from PySide6.QtWidgets import QFileDialog
13
16
 
14
17
  from je_editor.pyside_ui.main_ui.editor.editor_widget import EditorWidget
@@ -17,13 +20,20 @@ from je_editor.utils.file.save.save_file import write_file
17
20
 
18
21
  def choose_file_get_save_file_path(parent_qt_instance: EditorMain) -> bool:
19
22
  """
20
- :param parent_qt_instance: Pyside parent
21
- :return: save code edit content to file
23
+ 開啟「另存新檔」對話框,將編輯器內容儲存到檔案
24
+ Open "Save As" dialog and save editor content to file
25
+ :param parent_qt_instance: Pyside 主視窗 / Pyside parent
26
+ :return: 是否成功儲存檔案 / whether file was saved successfully
22
27
  """
23
28
  jeditor_logger.info("save_file_dialog.py choose_file_get_save_file_path"
24
29
  f" parent_qt_instance: {parent_qt_instance}")
30
+
31
+ # 取得目前分頁的編輯器元件
32
+ # Get current tab's editor widget
25
33
  widget = parent_qt_instance.tab_widget.currentWidget()
34
+
26
35
  if isinstance(widget, EditorWidget):
36
+ # 開啟檔案儲存對話框 / Open file save dialog
27
37
  file_path = QFileDialog().getSaveFileName(
28
38
  parent=parent_qt_instance,
29
39
  dir=os.getcwd(),
@@ -31,15 +41,27 @@ def choose_file_get_save_file_path(parent_qt_instance: EditorMain) -> bool:
31
41
  HTML file (*.html);;
32
42
  File (*.*)"""
33
43
  )[0]
44
+
45
+ # 確認使用者有選擇檔案路徑 / Ensure user selected a file path
34
46
  if file_path is not None and file_path != "":
47
+ # 更新目前檔案路徑 / Update current file path
35
48
  widget.current_file = file_path
49
+
50
+ # 將編輯器內容寫入檔案 / Write editor content to file
36
51
  write_file(file_path, widget.code_edit.toPlainText())
52
+
53
+ # 更新已開啟檔案管理字典 / Update opened file manager dictionary
37
54
  path = Path(file_path)
38
55
  file_is_open_manager_dict.update({str(path): str(path.name)})
56
+
57
+ # 若有自動儲存執行緒,更新其監控的檔案與編輯器
58
+ # If auto-save thread exists, update its file and editor reference
39
59
  if widget.code_save_thread is not None:
40
60
  widget.code_save_thread.file = file_path
41
61
  widget.code_save_thread.editor = widget.code_edit
62
+
63
+ # 更新分頁標題 / Update tab title
42
64
  widget.rename_self_tab()
43
65
  return True
44
66
  return False
45
- return False
67
+ return False
@@ -5,20 +5,45 @@ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapp
5
5
 
6
6
 
7
7
  class SearchResultBox(QWidget):
8
+ """
9
+ 搜尋結果對話框
10
+ Search result dialog box
11
+ """
8
12
 
9
13
  def __init__(self):
10
14
  jeditor_logger.info("Init SearchResultBox")
11
15
  super().__init__()
16
+
17
+ # 垂直佈局 (上到下)
18
+ # Vertical layout (top to bottom)
12
19
  self.box_layout = QBoxLayout(QBoxLayout.Direction.TopToBottom)
20
+
21
+ # 搜尋輸入框 / Search input field
13
22
  self.search_input = QLineEdit()
23
+
24
+ # 下一個搜尋按鈕 / Next search button
14
25
  self.search_next_button = QPushButton()
15
26
  self.search_next_button.setText(language_wrapper.language_word_dict.get("search_next_dialog_pushbutton"))
27
+
28
+ # 上一個搜尋按鈕 / Previous search button
16
29
  self.search_back_button = QPushButton()
17
30
  self.search_back_button.setText(language_wrapper.language_word_dict.get("search_back_dialog_pushbutton"))
31
+
32
+ # 水平佈局 (放置前後搜尋按鈕)
33
+ # Horizontal layout (for back/next buttons)
18
34
  self.box_h_layout = QHBoxLayout()
19
35
  self.box_h_layout.addWidget(self.search_back_button)
20
36
  self.box_h_layout.addWidget(self.search_next_button)
37
+
38
+ # 將元件加入主佈局
39
+ # Add widgets to main layout
21
40
  self.box_layout.addWidget(self.search_input)
22
41
  self.box_layout.addLayout(self.box_h_layout)
42
+
43
+ # 設定視窗標題
44
+ # Set window title
23
45
  self.setWindowTitle("Search Result")
24
- self.setLayout(self.box_layout)
46
+
47
+ # 套用主佈局
48
+ # Apply main layout
49
+ self.setLayout(self.box_layout)
@@ -5,20 +5,45 @@ from je_editor.utils.multi_language.multi_language_wrapper import language_wrapp
5
5
 
6
6
 
7
7
  class SearchBox(QWidget):
8
+ """
9
+ 搜尋框元件
10
+ Search box widget
11
+ """
8
12
 
9
13
  def __init__(self):
10
14
  jeditor_logger.info("Init SearchBox")
11
15
  super().__init__()
16
+
17
+ # 垂直佈局 (上到下)
18
+ # Vertical layout (top to bottom)
12
19
  self.box_layout = QBoxLayout(QBoxLayout.Direction.TopToBottom)
20
+
21
+ # 搜尋輸入框 / Search input field
13
22
  self.search_input = QLineEdit()
23
+
24
+ # 下一個搜尋按鈕 / Next search button
14
25
  self.search_next_button = QPushButton()
15
26
  self.search_next_button.setText(language_wrapper.language_word_dict.get("search_next_dialog_pushbutton"))
27
+
28
+ # 上一個搜尋按鈕 / Previous search button
16
29
  self.search_back_button = QPushButton()
17
30
  self.search_back_button.setText(language_wrapper.language_word_dict.get("search_back_dialog_pushbutton"))
31
+
32
+ # 水平佈局 (放置前後搜尋按鈕)
33
+ # Horizontal layout (for back/next buttons)
18
34
  self.box_h_layout = QHBoxLayout()
19
35
  self.box_h_layout.addWidget(self.search_back_button)
20
36
  self.box_h_layout.addWidget(self.search_next_button)
37
+
38
+ # 將元件加入主佈局
39
+ # Add widgets to main layout
21
40
  self.box_layout.addWidget(self.search_input)
22
41
  self.box_layout.addLayout(self.box_h_layout)
42
+
43
+ # 設定視窗標題 (支援多語系)
44
+ # Set window title (multi-language support)
23
45
  self.setWindowTitle(language_wrapper.language_word_dict.get("search_box_dialog_title"))
24
- self.setLayout(self.box_layout)
46
+
47
+ # 套用主佈局
48
+ # Apply main layout
49
+ self.setLayout(self.box_layout)
@@ -34,10 +34,10 @@ class DiffViewerWidget(QWidget):
34
34
 
35
35
  # === View → Theme switching (exclusive) / 主題切換(單選模式) ===
36
36
  theme_group = QActionGroup(self)
37
- theme_group.setExclusive(True) # 確保只能選擇一個主題
37
+ theme_group.setExclusive(True) # 確保只能選擇一個主題 / ensure only one theme can be selected
38
38
 
39
- dark_action = QAction("Dark Mode", self, checkable=True) # 深色模式
40
- light_action = QAction("Light Mode", self, checkable=True) # 淺色模式
39
+ dark_action = QAction("Dark Mode", self, checkable=True) # 深色模式 / dark mode
40
+ light_action = QAction("Light Mode", self, checkable=True) # 淺色模式 / light mode
41
41
 
42
42
  theme_group.addAction(dark_action)
43
43
  theme_group.addAction(light_action)
@@ -55,8 +55,8 @@ class DiffViewerWidget(QWidget):
55
55
 
56
56
  # === Layout / 版面配置 ===
57
57
  layout = QVBoxLayout(self)
58
- layout.setMenuBar(self.menubar) # 把選單列放在上方
59
- layout.addWidget(self.viewer) # 把差異檢視器放在主要區域
58
+ layout.setMenuBar(self.menubar) # 把選單列放在上方 / put menu bar at the top
59
+ layout.addWidget(self.viewer) # 把差異檢視器放在主要區域 / add diff viewer in main area
60
60
 
61
61
  def open_repo(self):
62
62
  """
@@ -67,16 +67,16 @@ class DiffViewerWidget(QWidget):
67
67
  if not path:
68
68
  return
69
69
  try:
70
- repo = Repo(path) # 嘗試載入 Git 專案
71
- diff_text = repo.git.diff() # 取得差異文字
70
+ repo = Repo(path) # 嘗試載入 Git 專案 / try to load Git repo
71
+ diff_text = repo.git.diff() # 取得差異文字 / get diff text
72
72
  if not diff_text.strip():
73
- # 如果沒有差異,顯示提示訊息
73
+ # 如果沒有差異,顯示提示訊息 / show info if no changes
74
74
  QMessageBox.information(self, "Info", "No changes in repo.")
75
75
  else:
76
- # 如果有差異,顯示在 viewer 中
76
+ # 如果有差異,顯示在 viewer 中 / show diff in viewer
77
77
  self.viewer.set_diff_text(diff_text)
78
78
  except Exception as e:
79
- # 如果開啟失敗,顯示錯誤訊息
79
+ # 如果開啟失敗,顯示錯誤訊息 / show error if failed
80
80
  QMessageBox.critical(self, "Error", f"Failed to open repo:\n{e}")
81
81
 
82
82
  def set_theme(self, mode: str):
@@ -87,4 +87,4 @@ class DiffViewerWidget(QWidget):
87
87
  if mode == "dark":
88
88
  self.viewer.set_dark_theme()
89
89
  else:
90
- self.viewer.set_light_theme()
90
+ self.viewer.set_light_theme()