je-editor 0.0.221__py3-none-any.whl → 0.0.223__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 (36) hide show
  1. je_editor/__init__.py +2 -2
  2. je_editor/code_scan/ruff_thread.py +33 -6
  3. je_editor/code_scan/watchdog_implement.py +42 -20
  4. je_editor/code_scan/watchdog_thread.py +54 -9
  5. je_editor/git_client/commit_graph.py +32 -43
  6. je_editor/git_client/{git.py → git_action.py} +1 -1
  7. je_editor/git_client/git_cli.py +4 -4
  8. je_editor/pyside_ui/browser/browser_download_window.py +41 -5
  9. je_editor/pyside_ui/browser/browser_serach_lineedit.py +25 -1
  10. je_editor/pyside_ui/browser/browser_view.py +56 -3
  11. je_editor/pyside_ui/browser/browser_widget.py +52 -22
  12. je_editor/pyside_ui/browser/main_browser_widget.py +72 -0
  13. je_editor/pyside_ui/git_ui/code_diff_compare/__init__.py +0 -0
  14. je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +90 -0
  15. je_editor/pyside_ui/git_ui/code_diff_compare/line_number_code_viewer.py +141 -0
  16. je_editor/pyside_ui/git_ui/code_diff_compare/multi_file_diff_viewer.py +88 -0
  17. je_editor/pyside_ui/git_ui/code_diff_compare/side_by_side_diff_widget.py +271 -0
  18. je_editor/pyside_ui/git_ui/git_client/__init__.py +0 -0
  19. je_editor/pyside_ui/git_ui/{git_branch_tree_widget.py → git_client/git_branch_tree_widget.py} +17 -14
  20. je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +799 -0
  21. je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +1 -1
  22. je_editor/pyside_ui/main_ui/main_editor.py +5 -8
  23. je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +17 -17
  24. je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +2 -2
  25. je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +21 -21
  26. je_editor/utils/multi_language/english.py +2 -1
  27. je_editor/utils/multi_language/traditional_chinese.py +2 -2
  28. {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/METADATA +3 -3
  29. {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/RECORD +34 -28
  30. je_editor/git_client/github.py +0 -50
  31. je_editor/pyside_ui/git_ui/git_client_gui.py +0 -291
  32. /je_editor/pyside_ui/git_ui/{commit_table.py → git_client/commit_table.py} +0 -0
  33. /je_editor/pyside_ui/git_ui/{graph_view.py → git_client/graph_view.py} +0 -0
  34. {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/WHEEL +0 -0
  35. {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/licenses/LICENSE +0 -0
  36. {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/top_level.txt +0 -0
@@ -1,291 +0,0 @@
1
- import traceback
2
-
3
- from PySide6.QtGui import QTextOption
4
- from PySide6.QtWidgets import QWidget, QLabel, QPushButton, QComboBox, QHBoxLayout, QListWidget, QPlainTextEdit, \
5
- QSizePolicy, QSplitter, QLineEdit, QVBoxLayout, QMessageBox, QFileDialog, QInputDialog
6
-
7
- from je_editor.utils.multi_language.multi_language_wrapper import language_wrapper
8
- from je_editor.git_client.git import Worker, GitService
9
- from je_editor.git_client.github import GitCloneHandler
10
-
11
-
12
- class Gitgui(QWidget):
13
-
14
- def __init__(self):
15
- super().__init__()
16
- self.git = GitService()
17
- self.clone_handler = GitCloneHandler()
18
- self.language_wrapper_get = language_wrapper.language_word_dict.get
19
- self._init_ui()
20
-
21
- def _init_ui(self):
22
- # Top controls
23
- self.repo_label = QLabel(self.language_wrapper_get("label_repo_initial"))
24
- self.btn_open = QPushButton(self.language_wrapper_get("btn_open_repo"))
25
- self.branch_combo = QComboBox()
26
- self.btn_checkout = QPushButton(self.language_wrapper_get("btn_switch_branch"))
27
- self.btn_pull = QPushButton(self.language_wrapper_get("btn_pull"))
28
- self.btn_push = QPushButton(self.language_wrapper_get("btn_push"))
29
- self.remote_combo = QComboBox()
30
- self.clone_button = QPushButton(self.language_wrapper_get("btn_clone_remote"))
31
- self.clone_button.clicked.connect(self._on_clone_remote_repo)
32
-
33
- top = QHBoxLayout()
34
- top.addWidget(self.repo_label, 2)
35
- top.addWidget(self.btn_open)
36
- top.addWidget(QLabel(self.language_wrapper_get("label_remote")))
37
- top.addWidget(self.remote_combo)
38
- top.addWidget(QLabel(self.language_wrapper_get("label_branch")))
39
- top.addWidget(self.branch_combo, 1)
40
- top.addWidget(self.btn_checkout)
41
- top.addWidget(self.btn_pull)
42
- top.addWidget(self.btn_push)
43
- top.addWidget(self.clone_button)
44
-
45
- # Left commits list
46
- self.commit_list = QListWidget()
47
- self.commit_list.setMinimumWidth(380)
48
-
49
- # Right diff viewer
50
- self.diff_view = QPlainTextEdit()
51
- self.diff_view.setReadOnly(True)
52
- self.diff_view.setWordWrapMode(QTextOption.WrapMode.NoWrap)
53
- self.diff_view.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
54
- self.diff_view.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
55
- mono = self.font()
56
- mono.setFamily("Consolas")
57
- mono.setPointSize(10)
58
- self.diff_view.setFont(mono)
59
-
60
- splitter = QSplitter()
61
- splitter.addWidget(self.commit_list)
62
- splitter.addWidget(self.diff_view)
63
- splitter.setStretchFactor(0, 0)
64
- splitter.setStretchFactor(1, 1)
65
-
66
- # Bottom commit box
67
- self.msg_edit = QLineEdit()
68
- self.msg_edit.setPlaceholderText(self.language_wrapper_get("placeholder_commit_message"))
69
- self.btn_stage_all = QPushButton(self.language_wrapper_get("btn_stage_all"))
70
- self.btn_commit = QPushButton(self.language_wrapper_get("btn_commit"))
71
-
72
- bottom = QHBoxLayout()
73
- bottom.addWidget(QLabel(self.language_wrapper_get("label_message")))
74
- bottom.addWidget(self.msg_edit, 1)
75
- bottom.addWidget(self.btn_stage_all)
76
- bottom.addWidget(self.btn_commit)
77
-
78
- # Layout
79
- center_layout = QVBoxLayout()
80
- center_layout.addLayout(top)
81
- center_layout.addWidget(splitter, 1)
82
- center_layout.addLayout(bottom)
83
- self.setLayout(center_layout)
84
-
85
- # Events
86
- self.btn_open.clicked.connect(self.on_open_repo)
87
- self.branch_combo.currentTextChanged.connect(self.on_branch_changed)
88
- self.btn_checkout.clicked.connect(self.on_checkout)
89
- self.commit_list.itemSelectionChanged.connect(self.on_commit_selected)
90
- self.btn_stage_all.clicked.connect(self.on_stage_all)
91
- self.btn_commit.clicked.connect(self.on_commit)
92
- self.btn_pull.clicked.connect(self.on_pull)
93
- self.btn_push.clicked.connect(self.on_push)
94
-
95
- self._update_controls(enabled=False)
96
-
97
- # ------------- UI helpers -------------
98
- def _update_controls(self, enabled: bool):
99
- for w in [
100
- self.branch_combo, self.btn_checkout, self.commit_list,
101
- self.btn_stage_all, self.btn_commit, self.btn_pull, self.btn_push, self.remote_combo
102
- ]:
103
- w.setEnabled(enabled)
104
-
105
- def _error(self, title: str, err: Exception):
106
- traceback.print_exc()
107
- QMessageBox.critical(self, title, f"{title}\n\n{err}")
108
-
109
- def _info(self, title: str, msg: str):
110
- QMessageBox.information(self, title, msg)
111
-
112
- # ------------- Event handlers -------------
113
- def on_open_repo(self):
114
- path = QFileDialog.getExistingDirectory(self, self.language_wrapper_get("dialog_choose_repo"))
115
- if not path:
116
- return
117
- try:
118
- self.git.open_repo(path)
119
- self.repo_label.setText(f"Repo: {path}")
120
- self._refresh_branches()
121
- self._refresh_remotes()
122
- self._update_controls(enabled=True)
123
- self._load_commits_async()
124
- except Exception as e:
125
- self._error(self.language_wrapper_get("err_open_repo"), e)
126
-
127
- def _refresh_remotes(self):
128
- self.remote_combo.clear()
129
- try:
130
- remotes = self.git.remotes()
131
- self.remote_combo.addItems(remotes if remotes else [self.language_wrapper_get("default_remote")])
132
- except Exception:
133
- self.remote_combo.addItem(self.language_wrapper_get("default_remote"))
134
-
135
- def _refresh_branches(self):
136
- self.branch_combo.blockSignals(True)
137
- self.branch_combo.clear()
138
- try:
139
- branches = self.git.list_branches()
140
- self.branch_combo.addItems(branches)
141
- cur = self.git.current_branch()
142
- idx = self.branch_combo.findText(cur)
143
- if idx >= 0:
144
- self.branch_combo.setCurrentIndex(idx)
145
- except Exception as e:
146
- self._error(self.language_wrapper_get("err_load_branches"), e)
147
- finally:
148
- self.branch_combo.blockSignals(False)
149
-
150
- def on_branch_changed(self, branch: str):
151
- if not branch:
152
- return
153
- self._load_commits_async(branch)
154
-
155
- def _load_commits_async(self, branch: str | None = None):
156
- if branch is None:
157
- try:
158
- branch = self.git.current_branch()
159
- except Exception:
160
- return
161
- self.commit_list.clear()
162
- self.diff_view.setPlainText("")
163
- self.worker = Worker(self.git.list_commits, branch, 200)
164
- self.worker.done.connect(self._on_commits_loaded)
165
- self.worker.start()
166
-
167
- def _on_commits_loaded(self, result, error):
168
- if error:
169
- self._error(self.language_wrapper_get("err_load_commits"), error)
170
- return
171
- for c in result:
172
- self.commit_list.addItem(f"{c['hexsha'][:8]} {c['date']} {c['author']} {c['summary']}")
173
- self.commit_list.setProperty("commit_data", result)
174
-
175
- def on_checkout(self):
176
- branch = self.branch_combo.currentText()
177
- if not branch:
178
- return
179
-
180
- def after(res, err):
181
- if err:
182
- self._error(self.language_wrapper_get("err_checkout"), err)
183
- else:
184
- self._refresh_branches()
185
- self._load_commits_async(branch)
186
- self._info(
187
- self.language_wrapper_get("info_checkout_title"),
188
- f"{self.language_wrapper_get('info_checkout_msg')} {branch}"
189
- )
190
- self.worker = Worker(self.git.checkout, branch)
191
- self.worker.done.connect(after)
192
- self.worker.start()
193
-
194
- def on_commit_selected(self):
195
- items = self.commit_list.selectedIndexes()
196
- if not items:
197
- return
198
- idx = items[0].row()
199
- data = self.commit_list.property("commit_data") or []
200
- if idx >= len(data):
201
- return
202
- sha = data[idx]["hexsha"]
203
-
204
- def after(res, err):
205
- if err:
206
- self._error(self.language_wrapper_get("err_read_diff"), err)
207
- else:
208
- self.diff_view.setPlainText(res)
209
-
210
- self.worker = Worker(self.git.show_diff_of_commit, sha)
211
- self.worker.done.connect(after)
212
- self.worker.start()
213
-
214
- def on_stage_all(self):
215
- def after(res, err):
216
- if err:
217
- self._error(self.language_wrapper_get("err_stage"), err)
218
- else:
219
- self._info(self.language_wrapper_get("info_stage_title"), self.language_wrapper_get("info_stage_msg"))
220
-
221
- self.worker = Worker(self.git.stage_all)
222
- self.worker.done.connect(after)
223
- self.worker.start()
224
-
225
- def on_commit(self):
226
- msg = self.msg_edit.text()
227
-
228
- def after(res, err):
229
- if err:
230
- self._error(self.language_wrapper_get("err_commit"), err)
231
- else:
232
- self.msg_edit.clear()
233
- self._load_commits_async()
234
- self._info(self.language_wrapper_get("info_commit_title"), self.language_wrapper_get("info_commit_msg"))
235
-
236
- self.worker = Worker(self.git.commit, msg)
237
- self.worker.done.connect(after)
238
- self.worker.start()
239
-
240
- def on_pull(self):
241
- remote = self.remote_combo.currentText() or self.language_wrapper_get("default_remote")
242
- branch = self.branch_combo.currentText()
243
-
244
- def after(res, err):
245
- if err:
246
- self._error(self.language_wrapper_get("err_pull"), err)
247
- else:
248
- self._load_commits_async()
249
- self._info(self.language_wrapper_get("info_pull_title"), str(res))
250
-
251
- self.worker = Worker(self.git.pull, remote, branch)
252
- self.worker.done.connect(after)
253
- self.worker.start()
254
-
255
- def on_push(self):
256
- remote = self.remote_combo.currentText() or self.language_wrapper_get("default_remote")
257
- branch = self.branch_combo.currentText()
258
-
259
- def after(res, err):
260
- if err:
261
- self._error(self.language_wrapper_get("err_push"), err)
262
- else:
263
- self._info(self.language_wrapper_get("info_push_title"), str(res))
264
-
265
- self.worker = Worker(self.git.push, remote, branch)
266
- self.worker.done.connect(after)
267
- self.worker.start()
268
-
269
- def _on_clone_remote_repo(self):
270
- """
271
- UI handler for cloning a remote repository.
272
- """
273
- url, ok = QInputDialog.getText(self,
274
- self.language_wrapper_get("dialog_clone_title"),
275
- self.language_wrapper_get("dialog_clone_prompt"))
276
- if not ok or not url.strip():
277
- return
278
-
279
- local_dir = QFileDialog.getExistingDirectory(self, self.language_wrapper_get("dialog_select_folder"))
280
- if not local_dir:
281
- return
282
-
283
- try:
284
- repo_path = self.clone_handler.clone_repo(url.strip(), local_dir)
285
- self.git.open_repo(repo_path)
286
- QMessageBox.information(self,
287
- self.language_wrapper_get("info_clone_success_title"),
288
- f"{self.language_wrapper_get('info_clone_success_msg')} {repo_path}")
289
- except Exception as e:
290
- QMessageBox.critical(self, self.language_wrapper_get("err_clone_failed_title"), str(e))
291
-