diff --git a/gitplusplus.cpp b/gitplusplus.cpp index 3073f51..cf65f6a 100644 --- a/gitplusplus.cpp +++ b/gitplusplus.cpp @@ -483,11 +483,28 @@ GitPlusPlusView::GitPlusPlusView(GitPlusPlusPlugin *plugin, KTextEditor::MainWin } }); - // Debounce timer for filesystem changes (avoid spamming refreshes) + // Debounce timer for filesystem/document changes (avoid spamming refreshes) m_fsDebounce.setSingleShot(true); m_fsDebounce.setInterval(500); connect(&m_fsDebounce, &QTimer::timeout, this, &GitPlusPlusView::updateStatus); + // Refresh status when any document is saved — this is a concrete event + // that likely changes the working tree state. + auto connectDocSave = [this](KTextEditor::Document *doc) { + connect(doc, &KTextEditor::Document::documentSavedOrUploaded, this, [this]() { + m_fsDebounce.start(); + }); + }; + connect(KTextEditor::Editor::instance(), &KTextEditor::Editor::documentCreated, + this, [this, connectDocSave](KTextEditor::Editor *, KTextEditor::Document *doc) { + connectDocSave(doc); + }); + // Connect already-open documents + const auto docs = KTextEditor::Editor::instance()->documents(); + for (auto *doc : docs) { + connectDocSave(doc); + } + // Initial refresh QMetaObject::invokeMethod(this, &GitPlusPlusView::updateStatus, Qt::QueuedConnection); QMetaObject::invokeMethod(this, &GitPlusPlusView::refreshBranches, Qt::QueuedConnection); @@ -686,28 +703,22 @@ void GitPlusPlusView::setupFileWatcher() if (gitDir.isEmpty()) return; - // Watch the git directory itself — picks up renames of index, HEAD, refs, etc. - // This is more robust than watching individual files which get replaced atomically. - QStringList watchPaths; - watchPaths << gitDir; - - // Also watch refs/heads for branch changes + // Only watch refs/heads for branch creation/deletion — a concrete event. + // Do NOT watch the .git directory itself or the index file: + // those fire on every git operation (index.lock create/delete) and cause + // cascading git-status calls that leave index.lock files behind. QString refsHeads = gitDir + QStringLiteral("/refs/heads"); if (QFileInfo::exists(refsHeads)) - watchPaths << refsHeads; + m_watcher->addPath(refsHeads); - m_watcher->addPaths(watchPaths); connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, [this](const QString &) { m_fsDebounce.start(); }); - // Watch HEAD file specifically — changes indicate branch switch - QString indexFile = gitDir + QStringLiteral("/index"); + + // Watch HEAD file only — changes indicate a branch switch (concrete event). QString headFile = gitDir + QStringLiteral("/HEAD"); - QStringList filePaths; - if (QFileInfo::exists(indexFile)) filePaths << indexFile; - if (QFileInfo::exists(headFile)) filePaths << headFile; - if (!filePaths.isEmpty()) { - m_watcher->addPaths(filePaths); + if (QFileInfo::exists(headFile)) { + m_watcher->addPath(headFile); connect(m_watcher, &QFileSystemWatcher::fileChanged, this, [this, headFile](const QString &path) { // Re-add: atomic renames remove the watch if (!m_watcher->files().contains(path)) { @@ -716,9 +727,9 @@ void GitPlusPlusView::setupFileWatcher() m_watcher->addPath(path); }); } - m_fsDebounce.start(); - // HEAD change means branch switch — refresh branches if (path == headFile) { + // Branch switch — refresh branches and status after a short delay + m_fsDebounce.start(); QTimer::singleShot(600, this, [this]() { refreshBranches(); }); } });