#ifndef GITPLUSPLUS_H #define GITPLUSPLUS_H #include #include #include #include #if KTEXTEDITOR_VERSION >= QT_VERSION_CHECK(6, 0, 0) #include #endif #include #include #include #include #include class GitPlusPlusView; class GitStatusModel; class QTreeView; class QListWidget; class QLineEdit; class QTextEdit; class QToolButton; class QLabel; class QComboBox; class QCheckBox; class QTabWidget; class QAction; class QSortFilterProxyModel; class QStringListModel; class QFileSystemWatcher; class QListWidgetItem; /** * Git++ Plugin - standalone KTextEditor plugin providing git operations. */ class GitPlusPlusPlugin : public KTextEditor::Plugin { Q_OBJECT public: #if KTEXTEDITOR_VERSION >= QT_VERSION_CHECK(6, 0, 0) explicit GitPlusPlusPlugin(QObject *parent, const KPluginMetaData &data, const QVariantList &args = {}); #else explicit GitPlusPlusPlugin(QObject *parent, const QVariantList &args = {}); #endif ~GitPlusPlusPlugin() override = default; QObject *createView(KTextEditor::MainWindow *mainWindow) override; }; /** * Per-main-window view providing the Git++ tool view. */ class GitPlusPlusView : public QObject { Q_OBJECT Q_PROPERTY(QByteArray lastDiff READ lastDiff NOTIFY diffShown) public: explicit GitPlusPlusView(GitPlusPlusPlugin *plugin, KTextEditor::MainWindow *mainWindow); ~GitPlusPlusView() override; QByteArray lastDiff() const { return m_lastDiff; } /** * Register an external action to appear in the diff context menu. * Ownership stays with the caller. */ Q_INVOKABLE void registerDiffAction(QAction *action); Q_SIGNALS: void diffShown(const QByteArray &diff, const QString &title); private Q_SLOTS: // Status void updateStatus(); void onProjectChanged(); void onStatusFinished(int exitCode, QProcess::ExitStatus exitStatus); // Stage/commit void stageSelected(); void unstageSelected(); void discardSelected(); void commitChanges(); void diffSelected(); void diffAll(); // Remote void push(); void pull(); void fetch(); // Branches void refreshBranches(); void onBranchFinished(int exitCode, QProcess::ExitStatus exitStatus); void checkoutBranch(); void createBranch(); void deleteBranch(); void compareBranch(); void createWorktree(); // Worktrees void refreshWorktrees(); void createWorktreeFromTab(); void removeWorktree(); void pruneWorktrees(); void worktreeContextMenu(const QPoint &pos); // Workspaces void refreshWorkspaces(); void createWorkspace(); void removeWorkspace(); void pruneWorkspaces(); void switchWorkspace(QListWidgetItem *item); void workspaceContextMenu(const QPoint &pos); // Stash void stashSave(); void stashApply(); void stashPop(); void stashDrop(); void stashDiff(); void refreshStashes(); void stashContextMenu(const QPoint &pos); // Log/commit void openCommit(); void refreshLog(); void logDiffAgainstHead(); void logShowCommit(); void logContextMenu(const QPoint &pos); // Branch context menu void branchContextMenu(const QPoint &pos); private: QString projectBaseDir() const; QProcess *gitProcess(const QStringList &args) const; void runSimpleGit(const QStringList &args, const QString &successMsg, const QString &errorMsg); void runRemoteGit(const QStringList &args, const QString &opName); void setMessage(const QString &text, bool isError = false); void computeDiffForFiles(const QStringList &files); void showDiffOutput(const QByteArray &diff, const QString &title, const QStringList &gitArgs = {}, int extraFlags = 0); void updateIndicators(); void setRemoteBusy(bool busy, const QString &opName = {}); void refreshAll(); void setupFileWatcher(); QStringList selectedFiles(bool staged) const; QString selectedBranch() const; QString selectedStash() const; void detectWorkspace(); QString resolveWorkspaceSource() const; QStringList workspaceRepoPaths() const; GitPlusPlusPlugin *m_plugin; KTextEditor::MainWindow *m_mainWindow; QWidget *m_toolView; // Tab widget QTabWidget *m_tabWidget; // --- Status tab --- QTreeView *m_treeView; GitStatusModel *m_model; QSortFilterProxyModel *m_proxy; QLineEdit *m_filterEdit; QTextEdit *m_commitMsgEdit; QCheckBox *m_amendCheck; QLabel *m_statusLabel; QToolButton *m_commitBtn; QToolButton *m_pushBtn; QToolButton *m_pullBtn; QToolButton *m_fetchBtn; QToolButton *m_stageBtn; QToolButton *m_unstageBtn; QToolButton *m_discardBtn; QToolButton *m_refreshBtn; QToolButton *m_stashBtn; // --- Branches tab --- QLineEdit *m_branchFilterEdit; QListWidget *m_branchList; QToolButton *m_branchCheckoutBtn; QToolButton *m_branchCreateBtn; QToolButton *m_branchDeleteBtn; QToolButton *m_branchCompareBtn; // --- Stashes tab --- QListWidget *m_stashList; QToolButton *m_stashSaveBtn; QToolButton *m_stashApplyBtn; QToolButton *m_stashPopBtn; QToolButton *m_stashDropBtn; // --- Worktrees tab --- QListWidget *m_worktreeList; // --- Workspaces tab --- QListWidget *m_workspaceList; QComboBox *m_repoCombo; // --- Log tab --- QListWidget *m_logList; // --- Tab visibility --- struct OptionalTab { QWidget *widget; QIcon icon; QString label; bool visible; }; QVector m_optionalTabs; void rebuildTabs(); void showTabContextMenu(const QPoint &pos); void saveTabVisibility(); void loadTabVisibility(); // --- Indicators --- QLabel *m_repoLabel; QLabel *m_statusBarWidget; // State QString m_gitDir; QString m_currentBranch; QStringList m_allBranches; QStringList m_remoteBranches; bool m_isDirty = false; QPointer m_remoteProc; int m_spinnerFrame = 0; QTimer m_fsDebounce; QFileSystemWatcher *m_watcher = nullptr; // Workspace state bool m_isWorkspace = false; QString m_workspaceDir; // this workspace's directory QString m_workspaceSourceDir; // resolved source workspace path QStringList m_workspaceRepos; // repo subdirs in source workspace // Diff extension mechanism QByteArray m_lastDiff; QList m_diffActions; }; #endif // GITPLUSPLUS_H