Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 18 additions & 24 deletions je_editor/git_client/git_action.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import os
from datetime import datetime
from typing import Any, Callable

from PySide6.QtCore import QThread, Signal
from git import Repo, GitCommandError, InvalidGitRepositoryError, NoSuchPathError

from je_editor.utils.logging.loggin_instance import jeditor_logger
Expand Down Expand Up @@ -35,7 +33,25 @@ def __init__(self) -> None:
self.repo: Repo | None = None
self.repo_path: str | None = None

def close(self) -> None:
"""
關掉目前的儲存庫
Close the repository currently open.

每個開著的 ``Repo`` 都帶著常駐的 ``git cat-file`` 子程序,不關掉就會一直
累積;開了幾十個之後,同一個程序裡連要開一條新執行緒都會變慢。
Every open ``Repo`` carries long-lived ``git cat-file`` child processes and
they pile up if it is never closed; after a few dozen, even starting a
thread in the same process gets slow.
"""
repo, self.repo = self.repo, None
if repo is not None:
repo.close()

def open_repo(self, path: str) -> None:
# 換儲存庫時先把上一個關掉,否則它的子程序會一直留著
# Close the previous one first, or its child processes stay behind
self.close()
try:
self.repo = Repo(path)
self.repo_path = path
Expand Down Expand Up @@ -251,25 +267,3 @@ def _ensure_repo(self) -> None:

# Null tree constant for initial commit diff
NULL_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904"


# Worker thread wrapper
class GitWorker(QThread):
"""
Runs a function in a separate thread to avoid blocking the UI.
Emits (result, error) when done.
"""
done = Signal(object, object)

def __init__(self, fn: Callable, *args: Any, **kwargs: Any) -> None:
super().__init__()
self.fn = fn
self.args = args
self.kwargs = kwargs

def run(self) -> None:
try:
res = self.fn(*self.args, **self.kwargs)
self.done.emit(res, None)
except Exception as e:
self.done.emit(None, e)
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,10 @@ def complete(self) -> None:
column = self.textCursor().positionInBlock()

self._complete_thread = QThread(self)
# 具名執行緒:萬一它在執行中被銷毀,Qt 的中止訊息才說得出是哪一條
# A named thread, so Qt's abort message says which one if it is ever
# destroyed while still running
self._complete_thread.setObjectName("JediCompleteThread")
self._complete_worker = _JediCompleteWorker(code, line, column, self.env)
self._complete_worker.moveToThread(self._complete_thread)
self._complete_thread.started.connect(self._complete_worker.run)
Expand Down Expand Up @@ -3122,12 +3126,35 @@ def closeEvent(self, event: QtGui.QCloseEvent) -> None:
self._lint_timer.stop()
self._diff_timer.stop()
self._complete_timer.stop()
self.stop_completion_thread()
self.lint_manager.stop()
self.diff_marker_manager.stop()
self.blame_manager.stop()
self.lsp_client.stop()
super().closeEvent(event)

def stop_completion_thread(self) -> None:
"""
等 jedi 補全的執行緒結束
Wait for the jedi completion thread to finish.

它是編輯器唯一一條沒有管理器代管的執行緒,因此要在這裡自己等;補全跑在
大檔上要一段時間,關閉時它還在跑的話 Qt 會直接讓程序中止。
It is the editor's one thread without a manager looking after it, so it is
waited for here: completion takes a while on a large file, and Qt aborts
the process outright if it is still running at the close.
"""
thread, self._complete_thread = self._complete_thread, None
if thread is None:
return
try:
if thread.isRunning():
thread.quit()
thread.wait()
except RuntimeError:
# 它已經跑完並被刪除了 / It already finished and was deleted
return

def mousePressEvent(self, event: QtGui.QMouseEvent) -> None:
"""
滑鼠點擊事件(Alt+點按用於多重游標)
Expand Down
4 changes: 4 additions & 0 deletions je_editor/pyside_ui/dialog/search_ui/search_replace_widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ class _SearchWorker(QThread):

def __init__(self, root: str, pattern: str, case_sensitive: bool, use_regex: bool) -> None:
super().__init__()
# 具名執行緒:萬一它在執行中被銷毀,Qt 的中止訊息才說得出是哪一條
# A named thread, so Qt's abort message says which one if it is ever
# destroyed while still running
self.setObjectName("SearchWorker")
self.root = root
self.pattern = pattern
self.case_sensitive = case_sensitive
Expand Down
Loading
Loading