diff --git a/kde/kate/ollie_kate.cpp b/kde/kate/ollie_kate.cpp index 068f860..dd6d94c 100644 --- a/kde/kate/ollie_kate.cpp +++ b/kde/kate/ollie_kate.cpp @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include @@ -25,33 +24,6 @@ K_PLUGIN_CLASS_WITH_JSON(OllieKatePlugin, "metadata.json") -// Helper: detect if text looks like a unified diff -static bool looksLikeDiff(const QString &text) -{ - if (text.isEmpty()) return false; - // Check for unified diff markers - return text.contains(QLatin1String("diff --git")) || - text.contains(QLatin1String("@@ ")) || - text.contains(QLatin1String("--- a/")) || - text.contains(QLatin1String("+++ b/")) || - (text.contains(QLatin1String("---")) && text.contains(QLatin1String("+++"))); -} - -// Helper: extract diff content from a widget tree (for Kate's DiffWidget) -static QString extractDiffFromWidget(QWidget *widget) -{ - // Kate's DiffWidget uses DiffEditor (QPlainTextEdit subclass) children - // In Raw/Unified mode, one editor contains the actual diff - auto editors = widget->findChildren(); - for (auto *editor : editors) { - QString text = editor->toPlainText(); - if (looksLikeDiff(text)) { - return text; - } - } - return QString(); -} - // --- Plugin --- OllieKatePlugin::OllieKatePlugin(QObject *parent, const KPluginMetaData &data, const QVariantList &args) @@ -207,10 +179,6 @@ OllieKateView::OllieKateView(OllieKatePlugin *plugin, KTextEditor::MainWindow *m // Kate project plugin's built-in Git widget integration setupProjectGitWidget(); - - // Hook into widget additions for diff widget integration - connect(mainWindow, &KTextEditor::MainWindow::widgetAdded, - this, &OllieKateView::onWidgetAdded); } OllieKateView::~OllieKateView() @@ -447,6 +415,20 @@ void OllieKateView::setupContextMenu(KTextEditor::View *view) startAction->setObjectName(QStringLiteral("ollie_ctx_start")); connect(startAction, &QAction::triggered, this, &OllieKateView::startSession); + // Git diff review actions (available when in a git repo) + QString baseDir = projectBaseDir(); + if (!baseDir.isEmpty()) { + auto *reviewStagedAction = menu->addAction(QIcon::fromTheme(QStringLiteral("vcs-diff")), + QStringLiteral("Ollie: Review Staged Changes")); + reviewStagedAction->setObjectName(QStringLiteral("ollie_ctx_review_staged")); + connect(reviewStagedAction, &QAction::triggered, this, &OllieKateView::reviewStagedChanges); + + auto *reviewUnstagedAction = menu->addAction(QIcon::fromTheme(QStringLiteral("vcs-diff")), + QStringLiteral("Ollie: Review Unstaged Changes")); + reviewUnstagedAction->setObjectName(QStringLiteral("ollie_ctx_review_unstaged")); + connect(reviewUnstagedAction, &QAction::triggered, this, &OllieKateView::reviewUnstagedChanges); + } + if (!v->selection()) return; auto *explainAction = menu->addAction(QIcon::fromTheme(QStringLiteral("help-contents")), @@ -706,67 +688,6 @@ void OllieKateView::onProjectTreeContextMenu(const QPoint &pos) menu.exec(m_projectTreeView->viewport()->mapToGlobal(pos)); } -void OllieKateView::onWidgetAdded(QWidget *widget) -{ - if (!widget) return; - - // Detect diff widgets by multiple heuristics: - // 1. Class name contains "Diff" - // 2. Has shouldClose() method (Kate's DiffWidget) - // 3. Object name contains "diff" - QString className = QString::fromLatin1(widget->metaObject()->className()); - QString objName = widget->objectName(); - - qDebug() << "Ollie: widgetAdded:" << className << objName; - - bool isDiffWidget = className.contains(QLatin1String("Diff"), Qt::CaseInsensitive) || - objName.contains(QLatin1String("diff"), Qt::CaseInsensitive) || - widget->metaObject()->indexOfMethod("shouldClose()") >= 0; - - if (isDiffWidget) { - qDebug() << "Ollie: detected DiffWidget, installing event filter on editors"; - - // Store the diff widget for later use - m_currentDiffWidget = widget; - - // Find DiffEditor children (QPlainTextEdit) and install event filter on them - auto editors = widget->findChildren(); - qDebug() << "Ollie: found" << editors.size() << "QPlainTextEdit children"; - for (auto *editor : editors) { - editor->installEventFilter(this); - } - } -} - -void OllieKateView::onDiffWidgetContextMenu(QWidget *diffWidget, const QPoint &pos) -{ - QMenu menu(diffWidget); - - auto *reviewAction = menu.addAction(QIcon::fromTheme(QStringLiteral("document-preview")), - QStringLiteral("Ollie: Review This Diff")); - connect(reviewAction, &QAction::triggered, this, [this, diffWidget]() { - reviewDiffFromWidget(diffWidget); - }); - - menu.exec(diffWidget->mapToGlobal(pos)); -} - -void OllieKateView::reviewDiffFromWidget(QWidget *diffWidget) -{ - // Extract diff content from Kate's DiffWidget - // DiffWidget uses DiffEditor (QPlainTextEdit) children to display diff - QString diff = extractDiffFromWidget(diffWidget); - - if (diff.isEmpty()) return; - - ensureAgent(); - if (m_agentId.isEmpty()) return; - - QString prompt = QStringLiteral("Read-only task. Review the following diff. Do not edit files. Identify correctness bugs, regressions, security issues, missing tests, and maintainability concerns. For each finding, explain the impact and cite the relevant hunk. If there are no findings, say so explicitly.\n\n```diff\n") - + diff + QStringLiteral("\n```"); - m_9p->write(agentPath() + "/prompt", prompt.toUtf8()); -} - void OllieKateView::reviewStagedChanges() { QString baseDir = projectBaseDir(); @@ -996,46 +917,10 @@ void OllieKateView::setupGhostProvider() } } -// --- Event Filter (ghost text key handling + diff context menu) --- - -// Helper to check if widget is inside a diff widget -static bool isInsideDiffWidget(QWidget *widget, QWidget *diffWidget) -{ - QWidget *parent = widget->parentWidget(); - while (parent) { - if (parent == diffWidget) return true; - parent = parent->parentWidget(); - } - return false; -} +// --- Event Filter (ghost text key handling) --- bool OllieKateView::eventFilter(QObject *obj, QEvent *event) { - // Handle context menu for diff editors (QPlainTextEdit inside DiffWidget) - if (event->type() == QEvent::ContextMenu) { - auto *editor = qobject_cast(obj); - if (editor && m_currentDiffWidget && isInsideDiffWidget(editor, m_currentDiffWidget)) { - auto *contextEvent = static_cast(event); - - // Create the standard context menu - QMenu *menu = editor->createStandardContextMenu(); - - // Add separator and our action at the end - menu->addSeparator(); - auto *reviewAction = menu->addAction(QIcon::fromTheme(QStringLiteral("document-preview")), - QStringLiteral("Ollie: Review This Diff")); - connect(reviewAction, &QAction::triggered, this, [this]() { - if (m_currentDiffWidget) { - reviewDiffFromWidget(m_currentDiffWidget); - } - }); - - menu->exec(contextEvent->globalPos()); - delete menu; - return true; - } - } - if (event->type() == QEvent::KeyPress && m_ghost) { auto *keyEvent = static_cast(event); diff --git a/kde/kate/ollie_kate.h b/kde/kate/ollie_kate.h index e016559..8f6b3e9 100644 --- a/kde/kate/ollie_kate.h +++ b/kde/kate/ollie_kate.h @@ -62,7 +62,6 @@ protected: private slots: void onProjectChanged(); void heartbeat(); - void onWidgetAdded(QWidget *widget); void onGitTreeContextMenu(const QPoint &pos); public: @@ -81,7 +80,6 @@ private: void reviewStagedChanges(); void reviewUnstagedChanges(); void askAboutGitSelection(); - void reviewDiffFromWidget(QWidget *diffWidget); // Agent naming QString agentNameFromCwd(const QString &cwd); @@ -99,7 +97,6 @@ private: void setupProjectTreeContextMenu(); void setupGitPlusPlusDiffAction(); void setupProjectGitWidget(); - void onDiffWidgetContextMenu(QWidget *diffWidget, const QPoint &pos); void onProjectTreeContextMenu(const QPoint &pos); // Ghost text @@ -121,7 +118,6 @@ private: // Git widget integration QPointer m_gitTreeView; QPointer m_projectTreeView; - QPointer m_currentDiffWidget; }; #endif // OLLIE_KATE_PLUGIN_H