From 3642f8b743c6e94b17064a0142bb00d851ab479c Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Thu, 16 Jul 2026 04:42:07 +0200 Subject: [PATCH] Preserve selection during auto-refresh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Only refresh status model when git output actually changes (skip beginResetModel/endResetModel if raw output is identical) - Filesystem watcher triggers updateStatus only, not refreshAll — branch/stash/worktree lists only rebuild on explicit user actions - Branch list refreshes on HEAD file change (branch switch) with delay to avoid interrupting interactions --- gitplusplus.cpp | 10 +++++++--- gitstatusmodel.cpp | 4 ++++ gitstatusmodel.h | 1 + 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/gitplusplus.cpp b/gitplusplus.cpp index bfd174b..598861a 100644 --- a/gitplusplus.cpp +++ b/gitplusplus.cpp @@ -430,7 +430,7 @@ GitPlusPlusView::GitPlusPlusView(GitPlusPlusPlugin *plugin, KTextEditor::MainWin // Debounce timer for filesystem changes (avoid spamming refreshes) m_fsDebounce.setSingleShot(true); m_fsDebounce.setInterval(500); - connect(&m_fsDebounce, &QTimer::timeout, this, &GitPlusPlusView::refreshAll); + connect(&m_fsDebounce, &QTimer::timeout, this, &GitPlusPlusView::updateStatus); // Initial refresh QMetaObject::invokeMethod(this, &GitPlusPlusView::updateStatus, Qt::QueuedConnection); @@ -549,7 +549,7 @@ void GitPlusPlusView::setupFileWatcher() connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, [this](const QString &) { m_fsDebounce.start(); }); - // Still watch individual files as a fallback for systems where dir watching is coarse + // Watch HEAD file specifically — changes indicate branch switch QString indexFile = gitDir + QStringLiteral("/index"); QString headFile = gitDir + QStringLiteral("/HEAD"); QStringList filePaths; @@ -557,7 +557,7 @@ void GitPlusPlusView::setupFileWatcher() if (QFileInfo::exists(headFile)) filePaths << headFile; if (!filePaths.isEmpty()) { m_watcher->addPaths(filePaths); - connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this](const QString &path) { + connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this, headFile](const QString &path) { // Re-add: atomic renames remove the watch if (!m_watcher->files().contains(path)) { QTimer::singleShot(200, this, [this, path]() { @@ -566,6 +566,10 @@ void GitPlusPlusView::setupFileWatcher() }); } m_fsDebounce.start(); + // HEAD change means branch switch — refresh branches + if (path == headFile) { + QTimer::singleShot(600, this, [this]() { refreshBranches(); }); + } }); } } diff --git a/gitstatusmodel.cpp b/gitstatusmodel.cpp index d89f7e4..c94e94b 100644 --- a/gitstatusmodel.cpp +++ b/gitstatusmodel.cpp @@ -153,6 +153,10 @@ Qt::ItemFlags GitStatusModel::flags(const QModelIndex &index) const void GitStatusModel::parseStatus(const QByteArray &raw) { + if (raw == m_lastRaw) + return; + m_lastRaw = raw; + beginResetModel(); for (int i = 0; i < NodeCount; ++i) diff --git a/gitstatusmodel.h b/gitstatusmodel.h index c4e06d5..7b7a6cd 100644 --- a/gitstatusmodel.h +++ b/gitstatusmodel.h @@ -61,6 +61,7 @@ public: private: static constexpr quintptr TopLevelId = 0xFFFFFFFF; + QByteArray m_lastRaw; QList m_entries[NodeCount]; QString m_nodeNames[NodeCount]; QIcon m_nodeIcons[NodeCount];