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.
- je_editor/__init__.py +2 -2
- je_editor/code_scan/ruff_thread.py +33 -6
- je_editor/code_scan/watchdog_implement.py +42 -20
- je_editor/code_scan/watchdog_thread.py +54 -9
- je_editor/git_client/commit_graph.py +32 -43
- je_editor/git_client/{git.py → git_action.py} +1 -1
- je_editor/git_client/git_cli.py +4 -4
- je_editor/pyside_ui/browser/browser_download_window.py +41 -5
- je_editor/pyside_ui/browser/browser_serach_lineedit.py +25 -1
- je_editor/pyside_ui/browser/browser_view.py +56 -3
- je_editor/pyside_ui/browser/browser_widget.py +52 -22
- je_editor/pyside_ui/browser/main_browser_widget.py +72 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/__init__.py +0 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/code_diff_viewer_widget.py +90 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/line_number_code_viewer.py +141 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/multi_file_diff_viewer.py +88 -0
- je_editor/pyside_ui/git_ui/code_diff_compare/side_by_side_diff_widget.py +271 -0
- je_editor/pyside_ui/git_ui/git_client/__init__.py +0 -0
- je_editor/pyside_ui/git_ui/{git_branch_tree_widget.py → git_client/git_branch_tree_widget.py} +17 -14
- je_editor/pyside_ui/git_ui/git_client/git_client_gui.py +799 -0
- je_editor/pyside_ui/main_ui/ai_widget/langchain_interface.py +1 -1
- je_editor/pyside_ui/main_ui/main_editor.py +5 -8
- je_editor/pyside_ui/main_ui/menu/dock_menu/build_dock_menu.py +17 -17
- je_editor/pyside_ui/main_ui/menu/help_menu/build_help_menu.py +2 -2
- je_editor/pyside_ui/main_ui/menu/tab_menu/build_tab_menu.py +21 -21
- je_editor/utils/multi_language/english.py +2 -1
- je_editor/utils/multi_language/traditional_chinese.py +2 -2
- {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/METADATA +3 -3
- {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/RECORD +34 -28
- je_editor/git_client/github.py +0 -50
- je_editor/pyside_ui/git_ui/git_client_gui.py +0 -291
- /je_editor/pyside_ui/git_ui/{commit_table.py → git_client/commit_table.py} +0 -0
- /je_editor/pyside_ui/git_ui/{graph_view.py → git_client/graph_view.py} +0 -0
- {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/WHEEL +0 -0
- {je_editor-0.0.221.dist-info → je_editor-0.0.223.dist-info}/licenses/LICENSE +0 -0
- {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
|
-
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|