From 3204db4d38d95cf64a5f4073294b6f5fb587a419 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Wed, 4 Feb 2026 23:36:32 +0200 Subject: [PATCH 01/22] Git: started working on UI of commit widget We have a list of modified files, and basic layout. Next step is displaying the diff of current file - then link the preview with content of file. --- CMakeLists.txt | 10 +- build-appimage.sh | 2 +- src/plugins/git/CommitForm.cpp | 201 +++++++++++++++++++++++++++++++++ src/plugins/git/CommitForm.hpp | 24 ++++ src/plugins/git/CommitForm.ui | 139 +++++++++++++++++++++++ src/plugins/git/GitPlugin.cpp | 30 ++++- src/plugins/git/GitPlugin.hpp | 1 + 7 files changed, 398 insertions(+), 9 deletions(-) create mode 100644 src/plugins/git/CommitForm.cpp create mode 100644 src/plugins/git/CommitForm.hpp create mode 100644 src/plugins/git/CommitForm.ui diff --git a/CMakeLists.txt b/CMakeLists.txt index aba88dd..66ebb9d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -174,6 +174,9 @@ set(codepointer_sources src/plugins/git/GitCommit.ui src/plugins/git/GitPlugin.cpp src/plugins/git/GitPlugin.hpp + src/plugins/git/CommitForm.cpp + src/plugins/git/CommitForm.hpp + src/plugins/git/CommitForm.ui src/plugins/Terminal/TerminalPlugin.cpp src/plugins/Terminal/TerminalPlugin.hpp src/AnsiToHTML.cpp @@ -187,12 +190,7 @@ file(COPY "${CMAKE_SOURCE_DIR}/${ICON_NAME}.ico" DESTINATION "${CMAKE_BINARY_DIR configure_file(codepointer.qrc.in ${CMAKE_BINARY_DIR}/codepointer.qrc) configure_file(codepointer.desktop.in ${CMAKE_BINARY_DIR}/${CODEPOINTER_APP_NAME}.desktop) - -if (WIN32) - add_executable(codepointer WIN32 ${codepointer_sources} codepointer.rc) -else() - add_executable(codepointer ${codepointer_sources}) -endif() +add_executable(codepointer WIN32 ${codepointer_sources} codepointer.rc) if (!MINGW) set_property(TARGET codepointerPROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) diff --git a/build-appimage.sh b/build-appimage.sh index 020d9d5..cf9e20e 100755 --- a/build-appimage.sh +++ b/build-appimage.sh @@ -16,7 +16,7 @@ APP_VERSION="0.1.1" QT_VERSION="6.10.1" NAME="${APP_NAME}-v${APP_VERSION}${NAME_SUFFIX}-x86_64" -QTDIR="${HOME}/qt/${QT_VERSION}/gcc_64" +QTDIR="/usr/lib/qt6" export matrix_config_build_dir=ubuntu-gcc export PATH=$QTDIR/bin:$PATH export LD_LIBRARY_PATH=$QTDIR/lib:$LD_LIBRARY_PATH diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp new file mode 100644 index 0000000..a55e5e5 --- /dev/null +++ b/src/plugins/git/CommitForm.cpp @@ -0,0 +1,201 @@ +#include +#include +#include + +#include "CommitForm.hpp" +#include "GitPlugin.hpp" +#include "ui_CommitForm.h" + +enum class GitFileStatus { Modified, Added, Deleted, Renamed, Copied, Untracked, Unknown }; + +struct GitStatusEntry { + QString filename; + GitFileStatus status; + bool checked = false; +}; + +static auto parseGitStatus(QStringView statusOutput) -> QList { + auto out = QList{}; + + for (auto line : statusOutput.split('\n', Qt::SkipEmptyParts) | + std::views::filter([](auto l) { return l.size() >= 3; })) { + const auto x = line[0]; + const auto y = line[1]; + + out.append( + {line.mid(3).trimmed().toString(), (x == '?' && y == '?') ? GitFileStatus::Untracked + : (x == 'A' || y == 'A') ? GitFileStatus::Added + : (x == 'M' || y == 'M') ? GitFileStatus::Modified + : (x == 'D' || y == 'D') ? GitFileStatus::Deleted + : (x == 'R' || y == 'R') ? GitFileStatus::Renamed + : (x == 'C' || y == 'C') ? GitFileStatus::Copied + : GitFileStatus::Unknown}); + } + return out; +} + +class GitStatusTableModel final : public QAbstractTableModel { + // Q_OBJECT + + public: + explicit GitStatusTableModel(QList entries, QObject *parent = nullptr); + + auto rowCount(const QModelIndex &parent = {}) const -> int override; + auto columnCount(const QModelIndex &parent = {}) const -> int override; + auto data(const QModelIndex &index, int role) const -> QVariant override; + auto setData(const QModelIndex &index, const QVariant &value, int role) -> bool override; + auto flags(const QModelIndex &index) const -> Qt::ItemFlags override; + auto headerData(int section, Qt::Orientation orientation, int role) const -> QVariant override; + + auto setEntries(QList entries) -> void; + auto checkedEntries() const -> QList; + + private: + QList m_entries; + + static auto statusToText(GitFileStatus status) -> QString; +}; + +GitStatusTableModel::GitStatusTableModel(QList entries, QObject *parent) + : QAbstractTableModel(parent) { + m_entries = std::move(entries); +} + +auto GitStatusTableModel::rowCount(const QModelIndex &parent) const -> int { + return parent.isValid() ? 0 : m_entries.size(); +} + +auto GitStatusTableModel::columnCount(const QModelIndex &) const -> int { + return 3; // checkbox | filename | status +} + +auto GitStatusTableModel::data(const QModelIndex &index, int role) const -> QVariant { + if (!index.isValid()) { + return {}; + } + + const auto &e = m_entries.at(index.row()); + + if (index.column() == 0 && role == Qt::CheckStateRole) { + return e.checked ? Qt::Checked : Qt::Unchecked; + } + + if (role != Qt::DisplayRole) { + return {}; + } + + switch (index.column()) { + case 1: + return statusToText(e.status); + case 2: + return e.filename; + default: + return {}; + } +} + +auto GitStatusTableModel::setData(const QModelIndex &index, const QVariant &value, int role) + -> bool { + if (!index.isValid()) { + return false; + } + + if (index.column() == 0 && role == Qt::CheckStateRole) { + auto &e = m_entries[index.row()]; + e.checked = (value.toInt() == Qt::Checked); + emit dataChanged(index, index, {Qt::CheckStateRole}); + return true; + } + + return false; +} + +auto GitStatusTableModel::flags(const QModelIndex &index) const -> Qt::ItemFlags { + if (!index.isValid()) { + return Qt::NoItemFlags; + } + + auto f = Qt::ItemIsSelectable | Qt::ItemIsEnabled; + + if (index.column() == 0) { + f |= Qt::ItemIsUserCheckable; + } + + return f; +} + +auto GitStatusTableModel::headerData(int section, Qt::Orientation orientation, int role) const + -> QVariant { + if (orientation != Qt::Horizontal || role != Qt::DisplayRole) { + return {}; + } + + switch (section) { + case 0: + return tr("Commit"); + case 1: + return tr("Status"); + case 2: + return tr("File"); + default: + return {}; + } +} + +auto GitStatusTableModel::setEntries(QList entries) -> void { + beginResetModel(); + m_entries = std::move(entries); + endResetModel(); +} + +auto GitStatusTableModel::checkedEntries() const -> QList { + QList out; + for (const auto &e : m_entries) { + if (e.checked) { + out.append(e); + } + } + return out; +} + +auto GitStatusTableModel::statusToText(GitFileStatus status) -> QString { + switch (status) { + case GitFileStatus::Modified: + return QStringLiteral("Modified"); + case GitFileStatus::Added: + return QStringLiteral("Added"); + case GitFileStatus::Deleted: + return QStringLiteral("Deleted"); + case GitFileStatus::Renamed: + return QStringLiteral("Renamed"); + case GitFileStatus::Copied: + return QStringLiteral("Copied"); + case GitFileStatus::Untracked: + return QStringLiteral("Untracked"); + default: + return QStringLiteral("Unknown"); + } +} + +///////// +CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) + : QWidget(parent), ui(new Ui::CommitForm) { + ui->setupUi(this); + mdiClientName = tr("Commit"); + repoRoot = dir; + git = plugin; + + auto gitOutput = git->runGit({"-C", repoRoot, "status", "--porcelain"}); + auto status = parseGitStatus(gitOutput); + auto list = new GitStatusTableModel(status, ui->tableView); + ui->tableView->setModel(list); + ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + + auto *header = ui->tableView->horizontalHeader(); + header->setSectionResizeMode(0, QHeaderView::ResizeToContents); + header->setSectionResizeMode(1, QHeaderView::ResizeToContents); + // Make the last column stretch + header->setSectionResizeMode(2, QHeaderView::Stretch); +} + +CommitForm::~CommitForm() { delete ui; } diff --git a/src/plugins/git/CommitForm.hpp b/src/plugins/git/CommitForm.hpp new file mode 100644 index 0000000..195aad8 --- /dev/null +++ b/src/plugins/git/CommitForm.hpp @@ -0,0 +1,24 @@ +#pragma once + +#include +#include + +namespace Ui { +class CommitForm; +} + +class GitPlugin; + +class CommitForm : public QWidget, public qmdiClient +{ + Q_OBJECT + +public: + explicit CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent); + ~CommitForm(); + +private: + Ui::CommitForm *ui; + GitPlugin *git; + QString repoRoot; +}; diff --git a/src/plugins/git/CommitForm.ui b/src/plugins/git/CommitForm.ui new file mode 100644 index 0000000..a6ad75a --- /dev/null +++ b/src/plugins/git/CommitForm.ui @@ -0,0 +1,139 @@ + + + CommitForm + + + + 0 + 0 + 623 + 469 + + + + Form + + + + + + Qt::Orientation::Horizontal + + + + + + + true + + + commit message + + + + + + + + + Commit + + + + + + + Qt::Orientation::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + Files + + + + + + + + + + Select all + + + + + + + Select none + + + + + + + + + + + Diff + + + + + + + + + + + + + + Content + + + + + + + + + + + + + + + + diffPreview + modificationChanged(bool) + commitButton + setEnabled(bool) + + + 80 + 127 + + + 66 + 436 + + + + + diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index eb9cc24..f4ac9b4 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -20,6 +20,7 @@ #include "GlobalCommands.hpp" #include "iplugin.h" #include "plugins/git/CreateGitBranch.hpp" +#include "plugins/git/CommitForm.hpp" #include "ui_GitCommands.h" #include "ui_GitCommit.h" #include "widgets/AutoShrinkLabel.hpp" @@ -121,6 +122,7 @@ void GitPlugin::on_client_merged(qmdiHost *host) { revert->setToolTip(tr("Revert existing commits")); revert->setShortcut(QKeySequence("Ctrl+G, U")); commit->setToolTip(tr("Record changes to the repository")); + commit->setShortcut(QKeySequence("Ctrl+G, C")); stash->setToolTip(tr("tash away changes to dirty working directory")); branches->setToolTip(tr("List, create, or delete branches")); @@ -128,6 +130,7 @@ void GitPlugin::on_client_merged(qmdiHost *host) { connect(logProject, &QAction::triggered, this, &GitPlugin::logProjectHandler); connect(diffFile, &QAction::triggered, this, &GitPlugin::diffFileHandler); connect(revert, &QAction::triggered, this, &GitPlugin::revertFileHandler); + connect(commit, &QAction::triggered, this, &GitPlugin::commitHandler); auto menuName = "&Git"; host->menus.addActionGroup(menuName, "&Project"); @@ -247,7 +250,7 @@ void GitPlugin::refreshBranchesHandler() { form->branchListCombo->clear(); auto activeIndex = -1; auto delegate = static_cast(form->branchListCombo->itemDelegate()); - for (auto const &line : branches) { + for (auto const &line : std::as_const(branches)) { auto isActive = line.startsWith('*'); auto branchName = line.mid(2).trimmed(); if (branchName.isEmpty()) { @@ -322,6 +325,29 @@ void GitPlugin::deleteBranchHandler() { } } +void GitPlugin::commitHandler() { + auto manager = getManager(); + auto client = manager->getMdiServer()->getCurrentClient(); + auto filename = client->mdiClientFileName(); + if (filename.isEmpty()) { + // TODO - query the current project and use it for commits + qDebug() << "Cannot commit on an empty file" << filename; + return; + } + + auto repoRoot = QFileInfo(filename).absolutePath(); + repoRoot = detectRepoRoot(repoRoot); + qDebug() << "Current client" << filename << "at dir" << repoRoot; + if (repoRoot.isEmpty()) { + qDebug() << "Filename is not in any git repo" << filename; + return; + } + // qDebug() << "Will commit in repo" << repoRoot; + + auto commitForm = new CommitForm(repoRoot, this, manager); + mdiServer->addClient(commitForm); +} + void GitPlugin::logHandler(GitLog log, const QString &filename) { auto repoRoot = QFileInfo(filename).absolutePath(); repoRoot = detectRepoRoot(repoRoot); @@ -383,7 +409,7 @@ void GitPlugin::on_gitCommitClicked(const QModelIndex &mi) { auto diff = runGit({"-C", getConfig().getGitLastDir(), "show", widget->currentSha1, "--", filename}); auto shortSha1 = shortGitSha1(widget->currentSha1); - auto displayName = QString("%1-%2.diff").arg(shortSha1).arg(filename); + auto displayName = QString("%1-%2.diff").arg(shortSha1, filename); CommandArgs args = { {GlobalArguments::FileName, displayName}, {GlobalArguments::Content, diff}, diff --git a/src/plugins/git/GitPlugin.hpp b/src/plugins/git/GitPlugin.hpp index 9b70e65..fe911fd 100644 --- a/src/plugins/git/GitPlugin.hpp +++ b/src/plugins/git/GitPlugin.hpp @@ -41,6 +41,7 @@ class GitPlugin : public IPlugin { void diffBranchHandler(); void newBranchHandler(); void deleteBranchHandler(); + void commitHandler(); void logHandler(GitPlugin::GitLog log, const QString &filename); void on_gitCommitClicked(const QModelIndex &mi); void on_gitCommitDoubleClicked(const QModelIndex &mi); From ae2d16e30182d4285b9202149d65ab5b9394673e Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Thu, 5 Feb 2026 22:50:00 +0200 Subject: [PATCH 02/22] Git/commit: display diff of files When selected - a file, the diff of that file is displayed. We use the Qutepart, same as the main editor. That editor also shows the syntax of diff. I should use the text editor plugin to create the editor. This way the settings would follow, and double click would work (open the correct file). --- src/plugins/git/CommitForm.cpp | 67 +++++++++++++++++++++++++++++----- src/plugins/git/CommitForm.hpp | 18 +++++++-- src/plugins/git/CommitForm.ui | 27 ++++++++++++-- 3 files changed, 95 insertions(+), 17 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index a55e5e5..000c914 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -2,6 +2,8 @@ #include #include +#include + #include "CommitForm.hpp" #include "GitPlugin.hpp" #include "ui_CommitForm.h" @@ -38,7 +40,7 @@ class GitStatusTableModel final : public QAbstractTableModel { // Q_OBJECT public: - explicit GitStatusTableModel(QList entries, QObject *parent = nullptr); + explicit GitStatusTableModel(QObject *parent = nullptr); auto rowCount(const QModelIndex &parent = {}) const -> int override; auto columnCount(const QModelIndex &parent = {}) const -> int override; @@ -56,10 +58,7 @@ class GitStatusTableModel final : public QAbstractTableModel { static auto statusToText(GitFileStatus status) -> QString; }; -GitStatusTableModel::GitStatusTableModel(QList entries, QObject *parent) - : QAbstractTableModel(parent) { - m_entries = std::move(entries); -} +GitStatusTableModel::GitStatusTableModel(QObject *parent) : QAbstractTableModel(parent) {} auto GitStatusTableModel::rowCount(const QModelIndex &parent) const -> int { return parent.isValid() ? 0 : m_entries.size(); @@ -185,17 +184,65 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) repoRoot = dir; git = plugin; - auto gitOutput = git->runGit({"-C", repoRoot, "status", "--porcelain"}); - auto status = parseGitStatus(gitOutput); - auto list = new GitStatusTableModel(status, ui->tableView); - ui->tableView->setModel(list); + model = new GitStatusTableModel(ui->tableView); + // We will make it simpler for now + ui->modifiedFileNameLabel->hide(); + ui->modifiedFileContents->hide(); + + ui->tableView->setModel(model); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); + + { + editor = new Qutepart::Qutepart(this); + + // TODO - this would be epic + // editor = textEditorPlugin->fileNewEditor(); + + // TODO - I would like to get a highlighter from an extensions + editor->setHighlighter("diff.xml"); + + auto layout = ui->diffPreview->parentWidget()->layout(); + layout->replaceWidget(ui->diffPreview, editor); + ui->diffPreview->deleteLater(); + ui->diffPreview = editor; + } + + connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, + [this](const QItemSelection &selected, const QItemSelection &deselected) { + if (selected.indexes().size() == 0) { + newFileSelected({}); + return; + } + auto firstIndex = selected.indexes().first(); + auto idx = model->index(firstIndex.row(), 2); + auto fileName = model->data(idx, Qt::DisplayRole).toString(); + newFileSelected(fileName); + Q_UNUSED(deselected); + }); auto *header = ui->tableView->horizontalHeader(); header->setSectionResizeMode(0, QHeaderView::ResizeToContents); header->setSectionResizeMode(1, QHeaderView::ResizeToContents); - // Make the last column stretch header->setSectionResizeMode(2, QHeaderView::Stretch); + + updateGitStatus(); } CommitForm::~CommitForm() { delete ui; } + +void CommitForm::updateGitStatus() { + auto gitOutput = git->runGit({"-C", repoRoot, "status", "--porcelain"}); + auto status = parseGitStatus(gitOutput); + model->setEntries(status); +} + +void CommitForm::newFileSelected(const QString &filename) { + if (filename.isEmpty()) { + ui->diffPreview->setPlainText(""); + return; + } + + auto diff = git->runGit({"-C", repoRoot, "diff", filename}); + ui->diffPreview->setPlainText(diff); +} diff --git a/src/plugins/git/CommitForm.hpp b/src/plugins/git/CommitForm.hpp index 195aad8..302d88f 100644 --- a/src/plugins/git/CommitForm.hpp +++ b/src/plugins/git/CommitForm.hpp @@ -7,18 +7,28 @@ namespace Ui { class CommitForm; } +namespace Qutepart { +class Qutepart; +} + class GitPlugin; +class GitStatusTableModel; -class CommitForm : public QWidget, public qmdiClient -{ +class CommitForm : public QWidget, public qmdiClient { Q_OBJECT -public: + public: explicit CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent); ~CommitForm(); -private: + public slots: + void updateGitStatus(); + void newFileSelected(const QString &filename); + + private: Ui::CommitForm *ui; + GitStatusTableModel *model; GitPlugin *git; + Qutepart::Qutepart *editor; QString repoRoot; }; diff --git a/src/plugins/git/CommitForm.ui b/src/plugins/git/CommitForm.ui index a6ad75a..c8a01e7 100644 --- a/src/plugins/git/CommitForm.ui +++ b/src/plugins/git/CommitForm.ui @@ -21,6 +21,13 @@ + + + + Label + + + @@ -36,7 +43,7 @@ - Commit + &Commit @@ -69,17 +76,31 @@ + + + + Revert current + + + + + + + Revert selected + + + - Select all + Select &all - Select none + Select &none From cb5dc0f0c593c1b9d31895a9752580bcab0ba484 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Fri, 6 Feb 2026 18:20:14 +0200 Subject: [PATCH 03/22] Git: started working on revert I can revert a single item, and multiple is coded, but not tested yet. --- src/plugins/git/CommitForm.cpp | 99 ++++++++++++++++++++++++++++++++-- src/plugins/git/CommitForm.hpp | 5 ++ src/plugins/git/CommitForm.ui | 15 +++++- 3 files changed, 113 insertions(+), 6 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 000c914..46b29b6 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -42,6 +43,7 @@ class GitStatusTableModel final : public QAbstractTableModel { public: explicit GitStatusTableModel(QObject *parent = nullptr); + // Re-implementation rom QAbstractTableModel auto rowCount(const QModelIndex &parent = {}) const -> int override; auto columnCount(const QModelIndex &parent = {}) const -> int override; auto data(const QModelIndex &index, int role) const -> QVariant override; @@ -49,8 +51,11 @@ class GitStatusTableModel final : public QAbstractTableModel { auto flags(const QModelIndex &index) const -> Qt::ItemFlags override; auto headerData(int section, Qt::Orientation orientation, int role) const -> QVariant override; + // Public API auto setEntries(QList entries) -> void; auto checkedEntries() const -> QList; + auto setAllChecked(bool checked) -> void; + auto hasAnyChecked() const -> bool; private: QList m_entries; @@ -176,6 +181,30 @@ auto GitStatusTableModel::statusToText(GitFileStatus status) -> QString { } } +void GitStatusTableModel::setAllChecked(bool checked) { + if (m_entries.isEmpty()) { + return; + } + + for (auto &e : m_entries) { + e.checked = checked; + } + + const QModelIndex topLeft = index(0, 0); + const QModelIndex bottomRight = index(rowCount() - 1, 0); + + emit dataChanged(topLeft, bottomRight, {Qt::CheckStateRole}); +} + +bool GitStatusTableModel::hasAnyChecked() const { + for (const auto &e : m_entries) { + if (e.checked) { + return true; + } + } + return false; +} + ///////// CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) : QWidget(parent), ui(new Ui::CommitForm) { @@ -188,13 +217,15 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) // We will make it simpler for now ui->modifiedFileNameLabel->hide(); ui->modifiedFileContents->hide(); - ui->tableView->setModel(model); ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); + ui->revertSelectedButton->setEnabled(false); + ui->commitMessage->setFocusPolicy(Qt::StrongFocus); { editor = new Qutepart::Qutepart(this); + editor->setReadOnly(true); // TODO - this would be epic // editor = textEditorPlugin->fileNewEditor(); @@ -208,6 +239,15 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) ui->diffPreview = editor; } + auto *header = ui->tableView->horizontalHeader(); + header->setSectionResizeMode(0, QHeaderView::ResizeToContents); + header->setSectionResizeMode(1, QHeaderView::ResizeToContents); + header->setSectionResizeMode(2, QHeaderView::Stretch); + + connect(ui->revertCurrentButton, &QAbstractButton::clicked, this, + &CommitForm::revertCurrentImpl); + connect(ui->revertSelectedButton, &QAbstractButton::clicked, this, + &CommitForm::revertSelectionImpl); connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this](const QItemSelection &selected, const QItemSelection &deselected) { if (selected.indexes().size() == 0) { @@ -220,21 +260,51 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) newFileSelected(fileName); Q_UNUSED(deselected); }); + connect(model, &QAbstractItemModel::dataChanged, this, + [this](const QModelIndex &, const QModelIndex &, const QList &roles) { + if (!roles.isEmpty() && !roles.contains(Qt::CheckStateRole)) { + return; + } - auto *header = ui->tableView->horizontalHeader(); - header->setSectionResizeMode(0, QHeaderView::ResizeToContents); - header->setSectionResizeMode(1, QHeaderView::ResizeToContents); - header->setSectionResizeMode(2, QHeaderView::Stretch); + ui->revertSelectedButton->setEnabled(!model->checkedEntries().isEmpty()); + }); + connect(model, &QAbstractItemModel::modelReset, this, + [this]() { ui->revertSelectedButton->setEnabled(false); }); + ui->revertSelectedButton->setEnabled(false); + + connect(ui->selectAllButton, &QAbstractButton::clicked, this, [this]() { + model->setAllChecked(true); + ui->revertSelectedButton->setEnabled(true); + }); + connect(ui->selectNoneButton, &QAbstractButton::clicked, this, [this]() { + model->setAllChecked(false); + ui->revertSelectedButton->setEnabled(false); + }); updateGitStatus(); } CommitForm::~CommitForm() { delete ui; } +void CommitForm::keyPressEvent(QKeyEvent *event) { + if (event->key() == Qt::Key_Escape) { + if (editor) { + editor->setFocus(Qt::ShortcutFocusReason); + event->accept(); + return; + } + } + + QWidget::keyPressEvent(event); +} + void CommitForm::updateGitStatus() { auto gitOutput = git->runGit({"-C", repoRoot, "status", "--porcelain"}); auto status = parseGitStatus(gitOutput); model->setEntries(status); + if (model->rowCount() > 0) { + ui->tableView->selectRow(0); + } } void CommitForm::newFileSelected(const QString &filename) { @@ -246,3 +316,22 @@ void CommitForm::newFileSelected(const QString &filename) { auto diff = git->runGit({"-C", repoRoot, "diff", filename}); ui->diffPreview->setPlainText(diff); } + +void CommitForm::revertCurrentImpl() {} + +void CommitForm::revertSelectionImpl() { + auto checked = model->checkedEntries(); + if (checked.isEmpty()) { + return; + } + + auto args = QStringList{"-C", repoRoot, "checkout"}; + for (auto &c : std::as_const(checked)) { + args.push_back(c.filename); + } + + auto res = git->runGit(args); + qDebug() << res; + ui->gitOutput->setText(res); + updateGitStatus(); +} diff --git a/src/plugins/git/CommitForm.hpp b/src/plugins/git/CommitForm.hpp index 302d88f..9d9fd46 100644 --- a/src/plugins/git/CommitForm.hpp +++ b/src/plugins/git/CommitForm.hpp @@ -21,9 +21,14 @@ class CommitForm : public QWidget, public qmdiClient { explicit CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent); ~CommitForm(); + protected: + void keyPressEvent(QKeyEvent *event) override; + public slots: void updateGitStatus(); void newFileSelected(const QString &filename); + void revertCurrentImpl(); + void revertSelectionImpl(); private: Ui::CommitForm *ui; diff --git a/src/plugins/git/CommitForm.ui b/src/plugins/git/CommitForm.ui index c8a01e7..a77b382 100644 --- a/src/plugins/git/CommitForm.ui +++ b/src/plugins/git/CommitForm.ui @@ -98,7 +98,7 @@ - + Select &none @@ -136,6 +136,19 @@ + + + + + 0 + 0 + + + + + + + From 6fda59262cc7822038c7e9e7fb3cecef0e0db76f Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Fri, 6 Feb 2026 20:01:21 +0200 Subject: [PATCH 04/22] Git: capture output+exit code, revert works 1) When running git - return also the exit code. 2) (fix code compilation) 3) If on revert this fails - do not update file list. 4) Handle revert of single, and multiple file. --- src/plugins/git/CommitForm.cpp | 33 +++++++++++++++------ src/plugins/git/CreateGitBranch.cpp | 9 +++--- src/plugins/git/GitPlugin.cpp | 45 +++++++++++++++++++---------- src/plugins/git/GitPlugin.hpp | 3 +- 4 files changed, 61 insertions(+), 29 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 46b29b6..28aae9b 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -270,7 +270,6 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) }); connect(model, &QAbstractItemModel::modelReset, this, [this]() { ui->revertSelectedButton->setEnabled(false); }); - ui->revertSelectedButton->setEnabled(false); connect(ui->selectAllButton, &QAbstractButton::clicked, this, [this]() { model->setAllChecked(true); @@ -299,7 +298,7 @@ void CommitForm::keyPressEvent(QKeyEvent *event) { } void CommitForm::updateGitStatus() { - auto gitOutput = git->runGit({"-C", repoRoot, "status", "--porcelain"}); + auto [gitOutput, exitCode] = git->runGit({"-C", repoRoot, "status", "--porcelain"}); auto status = parseGitStatus(gitOutput); model->setEntries(status); if (model->rowCount() > 0) { @@ -313,11 +312,26 @@ void CommitForm::newFileSelected(const QString &filename) { return; } - auto diff = git->runGit({"-C", repoRoot, "diff", filename}); - ui->diffPreview->setPlainText(diff); + auto [output, exitCode] = git->runGit({"-C", repoRoot, "diff", filename}); + if (exitCode != 0) { + ui->commitLogLabel->setText(output); + return; + } + ui->commitLogLabel->setText(""); + ui->diffPreview->setPlainText(output); } -void CommitForm::revertCurrentImpl() {} +void CommitForm::revertCurrentImpl() { + auto selected = ui->tableView->currentIndex(); + auto idx = model->index(selected.row(), 2); + auto fileName = model->data(idx, Qt::DisplayRole).toString(); + auto args = QStringList{"-C", repoRoot, "checkout", fileName}; + auto [output, exitCode] = git->runGit(args); + ui->gitOutput->setText(output); + if (exitCode == 0) { + updateGitStatus(); + } +} void CommitForm::revertSelectionImpl() { auto checked = model->checkedEntries(); @@ -330,8 +344,9 @@ void CommitForm::revertSelectionImpl() { args.push_back(c.filename); } - auto res = git->runGit(args); - qDebug() << res; - ui->gitOutput->setText(res); - updateGitStatus(); + auto [output, exitCode] = git->runGit(args); + ui->gitOutput->setText(output); + if (exitCode == 0) { + updateGitStatus(); + } } diff --git a/src/plugins/git/CreateGitBranch.cpp b/src/plugins/git/CreateGitBranch.cpp index 8ca84c3..d050ab6 100644 --- a/src/plugins/git/CreateGitBranch.cpp +++ b/src/plugins/git/CreateGitBranch.cpp @@ -60,12 +60,12 @@ void CreateGitBranch::verifyBranchName(const QString &newText) { } void CreateGitBranch::findLocalBranches() { - auto res = plugin->runGit({"branch"}); - if (res.isEmpty()) { + auto [output, exitCode] = plugin->runGit({"branch"}); + if (output.isEmpty()) { return; } this->availableBranches.clear(); - for (auto &line : res.split('\n', Qt::SkipEmptyParts)) { + for (auto &line : output.split('\n', Qt::SkipEmptyParts)) { auto branchName = line.trimmed(); if (branchName.startsWith("* ")) { branchName.remove(0, 2); @@ -100,5 +100,6 @@ QString CreateGitBranch::createBranchImplementation(const QString &branchName, b } else { args = {"branch", branchName}; } - return plugin->runGit(args); + auto [gitOutput, exitCode] = plugin->runGit(args); + return gitOutput; } diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index f4ac9b4..9370a9e 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -19,8 +19,8 @@ #include "GitPlugin.hpp" #include "GlobalCommands.hpp" #include "iplugin.h" -#include "plugins/git/CreateGitBranch.hpp" #include "plugins/git/CommitForm.hpp" +#include "plugins/git/CreateGitBranch.hpp" #include "ui_GitCommands.h" #include "ui_GitCommit.h" #include "widgets/AutoShrinkLabel.hpp" @@ -233,7 +233,7 @@ void GitPlugin::revertFileHandler() { return; } auto args = QStringList{"restore", client->mdiClientFileName()}; - auto output = runGit(args); + auto [output, exitCode] = runGit(args); if (auto editor = dynamic_cast(client)) { editor->loadFile(filename); editor->loadContent(false); @@ -245,7 +245,7 @@ void GitPlugin::refreshBranchesHandler() { auto client = manager->getMdiServer()->getCurrentClient(); auto filename = client->mdiClientFileName(); auto repoRoot = getConfig().getGitLastDir(); - auto output = runGit({"-C", repoRoot, "branch", "-a"}); + auto [output, exitCode] = runGit({"-C", repoRoot, "branch", "-a"}); auto branches = output.split('\n', Qt::SkipEmptyParts); form->branchListCombo->clear(); auto activeIndex = -1; @@ -279,7 +279,7 @@ void GitPlugin::diffBranchHandler() { auto filename = client->mdiClientFileName(); auto repoRoot = QFileInfo(filename).absolutePath(); auto branch = form->branchListCombo->currentText(); - auto diff = runGit({"diff", branch}); + auto [diff, exitCode] = runGit({"diff", branch}); if (diff.isEmpty()) { return; } @@ -318,9 +318,13 @@ void GitPlugin::deleteBranchHandler() { if (reply == QMessageBox::Yes) { auto deleteBranchArg = cb->isChecked() ? "-D" : "-d"; auto args = QStringList{"branch", deleteBranchArg, branch}; - auto res = runGit(args); - form->gitOutput->setText(res); - form->gitOutput->setToolTip(res); + auto [output, exitCode] = runGit(args); + if (exitCode != 0) { + // TODO - display this error + return; + } + form->gitOutput->setText(output); + form->gitOutput->setToolTip(output); refreshBranchesHandler(); } } @@ -381,7 +385,12 @@ void GitPlugin::logHandler(GitLog log, const QString &filename) { getConfig().setGitLastDir(repoRoot); getConfig().setGitLastCommand(args.join(" ")); - auto output = runGit(args); + auto [output, exitCode] = runGit(args); + if (exitCode != 0) { + // ui->commitLogLabel->setText(output); + return; + } + model->setContent(output); form->listView->setModel(model); gitDock->raise(); @@ -406,8 +415,12 @@ void GitPlugin::on_gitCommitClicked(const QModelIndex &mi) { [this, widget](const QModelIndex &i) { auto manager = getManager(); auto filename = i.data().toString(); - auto diff = runGit({"-C", getConfig().getGitLastDir(), "show", - widget->currentSha1, "--", filename}); + auto [diff, exitCode] = runGit({"-C", getConfig().getGitLastDir(), "show", + widget->currentSha1, "--", filename}); + if (exitCode != 0) { + // TODO display this error + return; + } auto shortSha1 = shortGitSha1(widget->currentSha1); auto displayName = QString("%1-%2.diff").arg(shortSha1, filename); CommandArgs args = { @@ -453,13 +466,13 @@ void GitPlugin::on_gitCommitDoubleClicked(const QModelIndex &mi) { manager->handleCommandAsync(GlobalCommands::DisplayText, args); } -QString GitPlugin::runGit(const QStringList &args) { +std::tuple GitPlugin::runGit(const QStringList &args) { // qDebug() << "git " << args.join(" "); QProcess p; p.setProcessChannelMode(QProcess::ProcessChannelMode::MergedChannels); p.start(gitBinary, args); p.waitForFinished(); - return QString::fromUtf8(p.readAllStandardOutput()); + return {QString::fromUtf8(p.readAllStandardOutput()), p.exitCode()}; } QString GitPlugin::detectRepoRoot(const QString &filePath) { @@ -472,11 +485,13 @@ QString GitPlugin::detectRepoRoot(const QString &filePath) { QString GitPlugin::getDiff(const QString &path) { auto fi = QFileInfo(path); - return runGit({"-C", fi.absolutePath(), "diff"}); + auto [output, exitCode] = runGit({"-C", fi.absolutePath(), "diff"}); + return output; } QString GitPlugin::getRawCommit(const QString &sha1) { - return runGit({"-C", getConfig().getGitLastDir(), "show", sha1}); + auto [output, exitCode] = runGit({"-C", getConfig().getGitLastDir(), "show", sha1}); + return output; } void GitPlugin::restoreGitLog() { @@ -492,7 +507,7 @@ void GitPlugin::restoreGitLog() { auto args = cmd.split(" "); auto model = new CommitModel(this); form->label->setText(cmd); - auto output = runGit(args); + auto [output, exitCode] = runGit(args); model->setContent(output); form->listView->setModel(model); diff --git a/src/plugins/git/GitPlugin.hpp b/src/plugins/git/GitPlugin.hpp index fe911fd..edb760f 100644 --- a/src/plugins/git/GitPlugin.hpp +++ b/src/plugins/git/GitPlugin.hpp @@ -1,6 +1,7 @@ #pragma once #include "iplugin.h" +#include namespace Ui { class GitCommandsForm; @@ -47,7 +48,7 @@ class GitPlugin : public IPlugin { void on_gitCommitDoubleClicked(const QModelIndex &mi); public slots: - QString runGit(const QStringList &args); + std::tuple runGit(const QStringList &args); QString detectRepoRoot(const QString &path); QString getDiff(const QString &path); QString getRawCommit(const QString &sha1); From 6484ad12b499a6a76373e69e1289227d37d62a97 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 7 Feb 2026 00:15:19 +0200 Subject: [PATCH 05/22] Git: save/restore git commit window If you open a commit window, it will get restored when the app restarts. --- src/plugins/git/CommitForm.cpp | 4 ++++ src/plugins/git/CommitForm.hpp | 2 ++ src/plugins/git/GitPlugin.cpp | 17 +++++++++++++++++ src/plugins/git/GitPlugin.hpp | 2 ++ 4 files changed, 25 insertions(+) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 28aae9b..dc27118 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -285,6 +285,10 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) CommitForm::~CommitForm() { delete ui; } +QString CommitForm::mdiClientFileName() { + return QString("git:%1").arg(repoRoot); +} + void CommitForm::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { if (editor) { diff --git a/src/plugins/git/CommitForm.hpp b/src/plugins/git/CommitForm.hpp index 9d9fd46..871305f 100644 --- a/src/plugins/git/CommitForm.hpp +++ b/src/plugins/git/CommitForm.hpp @@ -20,6 +20,8 @@ class CommitForm : public QWidget, public qmdiClient { public: explicit CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent); ~CommitForm(); + + virtual QString mdiClientFileName() override; protected: void keyPressEvent(QKeyEvent *event) override; diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index 9370a9e..197e888 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -178,6 +178,23 @@ void GitPlugin::loadConfig(QSettings &settings) { restoreGitLog(); } +int GitPlugin::canOpenFile(const QString &fileName) { + auto url = QUrl (fileName); + if (url.scheme().isEmpty()) { + return 0; + } + return url.scheme() == "git" ? 5 : 0; +} + +qmdiClient *GitPlugin::openFile(const QString &fileName, int, int , int ) { + auto url = QUrl (fileName); + auto repoDir = url.path(); + auto manager = getManager(); + auto commitForm = new CommitForm(repoDir, this, manager); + mdiServer->addClient(commitForm); + return nullptr; +} + void GitPlugin::logFileHandler() { auto manager = getManager(); auto client = manager->getMdiServer()->getCurrentClient(); diff --git a/src/plugins/git/GitPlugin.hpp b/src/plugins/git/GitPlugin.hpp index edb760f..59f8fe4 100644 --- a/src/plugins/git/GitPlugin.hpp +++ b/src/plugins/git/GitPlugin.hpp @@ -32,6 +32,8 @@ class GitPlugin : public IPlugin { virtual void on_client_merged(qmdiHost *host) override; virtual void on_client_unmerged(qmdiHost *host) override; virtual void loadConfig(QSettings &settings) override; + virtual int canOpenFile(const QString &fileName) override; + virtual qmdiClient *openFile(const QString &fileName, int x = -1, int y = -1, int z = -1) override; public slots: void logFileHandler(); From 375053fb7a98c63cc85d4728b166e386d676615e Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 7 Feb 2026 17:38:29 +0200 Subject: [PATCH 06/22] Git commit: find root of repo fixes There are some regressions on finding the repo root. --- src/plugins/git/GitPlugin.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index 197e888..35a4c9d 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -338,6 +338,7 @@ void GitPlugin::deleteBranchHandler() { auto [output, exitCode] = runGit(args); if (exitCode != 0) { // TODO - display this error + qDebug() << "Command failed. Error" << exitCode << output; return; } form->gitOutput->setText(output); @@ -493,11 +494,15 @@ std::tuple GitPlugin::runGit(const QStringList &args) { } QString GitPlugin::detectRepoRoot(const QString &filePath) { - QProcess p; - p.setWorkingDirectory(QFileInfo(filePath).absolutePath()); - p.start(gitBinary, {"rev-parse", "--show-toplevel"}); - p.waitForFinished(); - return QString::fromUtf8(p.readAllStandardOutput()).trimmed(); + auto dir = QFileInfo(filePath).absolutePath(); + auto args = QStringList{"-C", dir, "rev-parse", "--show-toplevel"}; + auto [output, exitCode] = runGit(args); + if (exitCode != 0) { + qDebug() << "detectRepoRoot failed, with error" << exitCode << "output" << output + << "args:" << args; + return {}; + } + return output.trimmed(); } QString GitPlugin::getDiff(const QString &path) { From 540f26dd516cddf7487632e84252cf2d20dd5e7c Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 7 Feb 2026 18:31:58 +0200 Subject: [PATCH 07/22] clang-format --- src/plugins/git/CommitForm.cpp | 4 +--- src/plugins/git/CommitForm.hpp | 2 +- src/plugins/git/GitPlugin.cpp | 8 ++++---- src/plugins/git/GitPlugin.hpp | 3 ++- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index dc27118..499cfd7 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -285,9 +285,7 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) CommitForm::~CommitForm() { delete ui; } -QString CommitForm::mdiClientFileName() { - return QString("git:%1").arg(repoRoot); -} +QString CommitForm::mdiClientFileName() { return QString("git:%1").arg(repoRoot); } void CommitForm::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { diff --git a/src/plugins/git/CommitForm.hpp b/src/plugins/git/CommitForm.hpp index 871305f..b84004f 100644 --- a/src/plugins/git/CommitForm.hpp +++ b/src/plugins/git/CommitForm.hpp @@ -20,7 +20,7 @@ class CommitForm : public QWidget, public qmdiClient { public: explicit CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent); ~CommitForm(); - + virtual QString mdiClientFileName() override; protected: diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index 35a4c9d..18851e0 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -179,19 +179,19 @@ void GitPlugin::loadConfig(QSettings &settings) { } int GitPlugin::canOpenFile(const QString &fileName) { - auto url = QUrl (fileName); + auto url = QUrl(fileName); if (url.scheme().isEmpty()) { return 0; } return url.scheme() == "git" ? 5 : 0; } -qmdiClient *GitPlugin::openFile(const QString &fileName, int, int , int ) { - auto url = QUrl (fileName); +qmdiClient *GitPlugin::openFile(const QString &fileName, int, int, int) { + auto url = QUrl(fileName); auto repoDir = url.path(); auto manager = getManager(); auto commitForm = new CommitForm(repoDir, this, manager); - mdiServer->addClient(commitForm); + mdiServer->addClient(commitForm); return nullptr; } diff --git a/src/plugins/git/GitPlugin.hpp b/src/plugins/git/GitPlugin.hpp index 59f8fe4..63c2ae2 100644 --- a/src/plugins/git/GitPlugin.hpp +++ b/src/plugins/git/GitPlugin.hpp @@ -33,7 +33,8 @@ class GitPlugin : public IPlugin { virtual void on_client_unmerged(qmdiHost *host) override; virtual void loadConfig(QSettings &settings) override; virtual int canOpenFile(const QString &fileName) override; - virtual qmdiClient *openFile(const QString &fileName, int x = -1, int y = -1, int z = -1) override; + virtual qmdiClient *openFile(const QString &fileName, int x = -1, int y = -1, + int z = -1) override; public slots: void logFileHandler(); From a284fe4b03131440883661354d2b3aec4d169b62 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 7 Feb 2026 23:47:24 +0200 Subject: [PATCH 08/22] Git/CommitForm: use the standard editor in the Diff When the commit form now queries the text editor plugin, and creates the mdi editor from it. Now the settings of the editors, will be used for the diff viewer. Problems: - Clicking a diff, does not open the corresponding file. --- src/plugins/git/CommitForm.cpp | 29 +++++++++++++++++------ src/plugins/texteditor/texteditor_plg.cpp | 2 +- src/widgets/qmdieditor.cpp | 2 +- src/widgets/qmdieditor.h | 7 +++++- 4 files changed, 30 insertions(+), 10 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 499cfd7..8f0bc18 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -7,7 +7,9 @@ #include "CommitForm.hpp" #include "GitPlugin.hpp" +#include "plugins/texteditor/texteditor_plg.h" #include "ui_CommitForm.h" +#include "widgets/qmdieditor.h" enum class GitFileStatus { Modified, Added, Deleted, Renamed, Copied, Untracked, Unknown }; @@ -224,19 +226,32 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) ui->commitMessage->setFocusPolicy(Qt::StrongFocus); { + auto layout = ui->diffPreview->parentWidget()->layout(); + +#if 0 editor = new Qutepart::Qutepart(this); editor->setReadOnly(true); - - // TODO - this would be epic - // editor = textEditorPlugin->fileNewEditor(); - - // TODO - I would like to get a highlighter from an extensions editor->setHighlighter("diff.xml"); - - auto layout = ui->diffPreview->parentWidget()->layout(); layout->replaceWidget(ui->diffPreview, editor); ui->diffPreview->deleteLater(); ui->diffPreview = editor; +#else + auto manager = git->getManager(); + auto plugin = manager->findPlugin("TextEditorPlugin"); + if (auto p = dynamic_cast(plugin)) { + auto client = p->fileNewEditor(); + if (auto e = dynamic_cast(client)) { + e->setLineNumbersVisible(false); + e->setReadOnly(true); + e->setMinimapVisible(false); + e->setHighlighter("diff.xml"); + e->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); + layout->replaceWidget(ui->diffPreview, e); + ui->diffPreview->deleteLater(); + ui->diffPreview = e->getEditor(); + } + } +#endif } auto *header = ui->tableView->horizontalHeader(); diff --git a/src/plugins/texteditor/texteditor_plg.cpp b/src/plugins/texteditor/texteditor_plg.cpp index af87dbe..d24e3eb 100644 --- a/src/plugins/texteditor/texteditor_plg.cpp +++ b/src/plugins/texteditor/texteditor_plg.cpp @@ -25,7 +25,7 @@ #include "widgets/qmdieditor.h" TextEditorPlugin::TextEditorPlugin() { - name = tr("Text editor plugin - based on QutePart"); + name = "TextEditorPlugin"; author = tr("Diego Iastrubni "); iVersion = 0; sVersion = "0.0.1"; diff --git a/src/widgets/qmdieditor.cpp b/src/widgets/qmdieditor.cpp index a72978f..e251cf8 100644 --- a/src/widgets/qmdieditor.cpp +++ b/src/widgets/qmdieditor.cpp @@ -49,8 +49,8 @@ #include "GlobalCommands.hpp" #include "plugins/texteditor/thememanager.h" -#include "qmdieditor.h" #include "widgets/BoldItemDelegate.hpp" +#include "widgets/qmdieditor.h" #include "widgets/textoperationswidget.h" #include "widgets/textpreview.h" #include "widgets/ui_bannermessage.h" diff --git a/src/widgets/qmdieditor.h b/src/widgets/qmdieditor.h index 12bd195..82982af 100644 --- a/src/widgets/qmdieditor.h +++ b/src/widgets/qmdieditor.h @@ -179,8 +179,13 @@ class qmdiEditor : public QWidget, public qmdiClient { } return textEditor->document()->isEmpty(); } - inline void foldTopLevel() const { textEditor->foldTopLevelBlocks(); }; + inline void foldTopLevel() const { textEditor->foldTopLevelBlocks(); } + inline void setMinimapVisible(bool value) const { textEditor->setMinimapVisible(value); } void setReadOnly(bool b); + inline QPlainTextEdit* getEditor() const { return textEditor; } + inline void setHighlighter(const QString &languageId) { + textEditor->setHighlighter(languageId); + } protected: virtual void focusInEvent(QFocusEvent *event) override; From ee452c7326941156b2ec3ee038037ed27693d01e Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sun, 8 Feb 2026 11:36:42 +0200 Subject: [PATCH 09/22] Git/CommitForm: remove direct dependency on Qutepart --- src/plugins/git/CommitForm.cpp | 9 +++++---- src/plugins/git/CommitForm.hpp | 5 ----- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 8f0bc18..fea1d58 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -3,8 +3,6 @@ #include #include -#include - #include "CommitForm.hpp" #include "GitPlugin.hpp" #include "plugins/texteditor/texteditor_plg.h" @@ -304,8 +302,8 @@ QString CommitForm::mdiClientFileName() { return QString("git:%1").arg(repoRoot) void CommitForm::keyPressEvent(QKeyEvent *event) { if (event->key() == Qt::Key_Escape) { - if (editor) { - editor->setFocus(Qt::ShortcutFocusReason); + if (ui->diffPreview) { + ui->diffPreview->setFocus(Qt::ShortcutFocusReason); event->accept(); return; } @@ -332,6 +330,9 @@ void CommitForm::newFileSelected(const QString &filename) { auto [output, exitCode] = git->runGit({"-C", repoRoot, "diff", filename}); if (exitCode != 0) { ui->commitLogLabel->setText(output); + if (auto editor = dynamic_cast(ui->commitLogLabel)) { + editor->updateInternalMappings(repoRoot); + } return; } ui->commitLogLabel->setText(""); diff --git a/src/plugins/git/CommitForm.hpp b/src/plugins/git/CommitForm.hpp index b84004f..317806e 100644 --- a/src/plugins/git/CommitForm.hpp +++ b/src/plugins/git/CommitForm.hpp @@ -7,10 +7,6 @@ namespace Ui { class CommitForm; } -namespace Qutepart { -class Qutepart; -} - class GitPlugin; class GitStatusTableModel; @@ -36,6 +32,5 @@ class CommitForm : public QWidget, public qmdiClient { Ui::CommitForm *ui; GitStatusTableModel *model; GitPlugin *git; - Qutepart::Qutepart *editor; QString repoRoot; }; From 3bb855a51bc49506a5ee6f3482615feb52d655c1 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sun, 8 Feb 2026 12:56:35 +0200 Subject: [PATCH 10/22] Git/Commit: opening files from diff work I just needed to setup the mdi host on the editor. --- src/plugins/git/CommitForm.cpp | 15 ++++++++++----- src/widgets/qmdieditor.cpp | 3 ++- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index fea1d58..628a20c 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -238,6 +238,7 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) auto plugin = manager->findPlugin("TextEditorPlugin"); if (auto p = dynamic_cast(plugin)) { auto client = p->fileNewEditor(); + client->mdiServer = git->mdiServer; if (auto e = dynamic_cast(client)) { e->setLineNumbersVisible(false); e->setReadOnly(true); @@ -329,14 +330,18 @@ void CommitForm::newFileSelected(const QString &filename) { auto [output, exitCode] = git->runGit({"-C", repoRoot, "diff", filename}); if (exitCode != 0) { - ui->commitLogLabel->setText(output); - if (auto editor = dynamic_cast(ui->commitLogLabel)) { - editor->updateInternalMappings(repoRoot); - } + qDebug() << QString("git - code=%1, output=[%2]").arg(exitCode).arg(output); + ui->commitLogLabel->setText(""); + ui->diffPreview->setPlainText(output); return; } - ui->commitLogLabel->setText(""); + ui->diffPreview->setPlainText(output); + if (auto editor = dynamic_cast(ui->diffPreview->parent()->parent())) { + editor->updateInternalMappings(repoRoot); + } else { + qDebug() << "Double click on diff will not work"; + } } void CommitForm::revertCurrentImpl() { diff --git a/src/widgets/qmdieditor.cpp b/src/widgets/qmdieditor.cpp index e251cf8..b8d782f 100644 --- a/src/widgets/qmdieditor.cpp +++ b/src/widgets/qmdieditor.cpp @@ -955,7 +955,8 @@ bool qmdiEditor::eventFilter(QObject *watched, QEvent *event) { auto text = block.text(); if (diffMetadata.mappings.contains(blockNumber)) { auto l = diffMetadata.mappings[blockNumber]; - auto pluginManager = dynamic_cast(mdiServer->mdiHost); + auto pluginManager = mdiServer ? + dynamic_cast(mdiServer->mdiHost) : nullptr; if (pluginManager) { // Lines start on the editor from 0 if (l.newLine >= 0) { From 79c249f5bd84a955d05b0238c8fe0242c4153537 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sun, 8 Feb 2026 13:01:44 +0200 Subject: [PATCH 11/22] all: code cleanups --- src/plugins/git/CommitForm.cpp | 59 ++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 628a20c..f752cc4 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -70,24 +70,21 @@ auto GitStatusTableModel::rowCount(const QModelIndex &parent) const -> int { } auto GitStatusTableModel::columnCount(const QModelIndex &) const -> int { - return 3; // checkbox | filename | status + // checkbox | filename | status + return 3; } auto GitStatusTableModel::data(const QModelIndex &index, int role) const -> QVariant { if (!index.isValid()) { return {}; } - const auto &e = m_entries.at(index.row()); - if (index.column() == 0 && role == Qt::CheckStateRole) { return e.checked ? Qt::Checked : Qt::Unchecked; } - if (role != Qt::DisplayRole) { return {}; } - switch (index.column()) { case 1: return statusToText(e.status); @@ -120,11 +117,9 @@ auto GitStatusTableModel::flags(const QModelIndex &index) const -> Qt::ItemFlags } auto f = Qt::ItemIsSelectable | Qt::ItemIsEnabled; - if (index.column() == 0) { f |= Qt::ItemIsUserCheckable; } - return f; } @@ -214,26 +209,31 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) git = plugin; model = new GitStatusTableModel(ui->tableView); - // We will make it simpler for now - ui->modifiedFileNameLabel->hide(); - ui->modifiedFileContents->hide(); - ui->tableView->setModel(model); - ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); - ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); - ui->revertSelectedButton->setEnabled(false); - ui->commitMessage->setFocusPolicy(Qt::StrongFocus); + // We will make it simpler for now, no inline editing. + // I hope in the future to add a way to edit the file itself here. + // What prevetns: + // 1. We don't have a notion of shared document. We cannot open the + // same "content" in different tabs. + // 2. When double clicking a line in a diff, the code directly opens the + // modified file. Instead we will need to modify the code, and somehow + // catch this event in this class, and navigate to the file. + // 3. 3 Color layuout would be strech on small screens. I would like that + // on smaller "displays" the editor would be bellow the diff view, and + // on larger screen on the side. Qt provides no such layout. + // Solution to this might be having 2 editors with shared document, and + // on resize hide/show the revevant one. Other alternative - move it + // between layouts. + { + ui->modifiedFileNameLabel->hide(); + ui->modifiedFileContents->hide(); + } + // This code is a back hack, I use instead of changing the UI file to use + // a qmdiEditor. I am unsure how can I see QtDesigner to allocate the widget + // in a non-standard way. Note how I request the editor plugin for a widget + // instead of creating one manually here. { auto layout = ui->diffPreview->parentWidget()->layout(); - -#if 0 - editor = new Qutepart::Qutepart(this); - editor->setReadOnly(true); - editor->setHighlighter("diff.xml"); - layout->replaceWidget(ui->diffPreview, editor); - ui->diffPreview->deleteLater(); - ui->diffPreview = editor; -#else auto manager = git->getManager(); auto plugin = manager->findPlugin("TextEditorPlugin"); if (auto p = dynamic_cast(plugin)) { @@ -250,9 +250,14 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) ui->diffPreview = e->getEditor(); } } -#endif } + ui->tableView->setModel(model); + ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); + ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); + ui->revertSelectedButton->setEnabled(false); + ui->commitMessage->setFocusPolicy(Qt::StrongFocus); + auto *header = ui->tableView->horizontalHeader(); header->setSectionResizeMode(0, QHeaderView::ResizeToContents); header->setSectionResizeMode(1, QHeaderView::ResizeToContents); @@ -337,6 +342,10 @@ void CommitForm::newFileSelected(const QString &filename) { } ui->diffPreview->setPlainText(output); + // FIXME: this looks way too ugly, + // Problem - the "editor" is not the correct widge + // The UI expects a QPlainTextEdit, and we have Widget that includes a + // QPlainTextEdit. if (auto editor = dynamic_cast(ui->diffPreview->parent()->parent())) { editor->updateInternalMappings(repoRoot); } else { From 64ccd1f57c93e4061058a8e4e42027c49f0aafd1 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sun, 8 Feb 2026 23:04:59 +0200 Subject: [PATCH 12/22] Git/CommitForm: revert asks for confirmation The revert comand asks for confirmation. --- src/plugins/git/CommitForm.cpp | 39 ++++++++++++++++++++++++++++++---- src/plugins/git/CommitForm.hpp | 1 + 2 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index f752cc4..0869fb4 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "CommitForm.hpp" #include "GitPlugin.hpp" @@ -256,6 +257,7 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows); ui->tableView->setSelectionMode(QAbstractItemView::SingleSelection); ui->revertSelectedButton->setEnabled(false); + ui->commitButton->setEnabled(false); ui->commitMessage->setFocusPolicy(Qt::StrongFocus); auto *header = ui->tableView->horizontalHeader(); @@ -269,6 +271,7 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) &CommitForm::revertSelectionImpl); connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this](const QItemSelection &selected, const QItemSelection &deselected) { + qDebug() << "selection model cahnged"; if (selected.indexes().size() == 0) { newFileSelected({}); return; @@ -285,15 +288,17 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) return; } - ui->revertSelectedButton->setEnabled(!model->checkedEntries().isEmpty()); + auto hasSelection = !model->checkedEntries().isEmpty(); + ui->revertSelectedButton->setEnabled(hasSelection); + ui->commitButton->setEnabled(hasSelection); }); connect(model, &QAbstractItemModel::modelReset, this, [this]() { ui->revertSelectedButton->setEnabled(false); }); connect(ui->selectAllButton, &QAbstractButton::clicked, this, [this]() { model->setAllChecked(true); - ui->revertSelectedButton->setEnabled(true); - }); +/* ui->revertSelectedButton->setEnabled(true); +*/ }); connect(ui->selectNoneButton, &QAbstractButton::clicked, this, [this]() { model->setAllChecked(false); ui->revertSelectedButton->setEnabled(false); @@ -346,7 +351,7 @@ void CommitForm::newFileSelected(const QString &filename) { // Problem - the "editor" is not the correct widge // The UI expects a QPlainTextEdit, and we have Widget that includes a // QPlainTextEdit. - if (auto editor = dynamic_cast(ui->diffPreview->parent()->parent())) { + if (auto editor = dynamic_cast(ui->diffPreview->parent()->parent())) { editor->updateInternalMappings(repoRoot); } else { qDebug() << "Double click on diff will not work"; @@ -357,6 +362,18 @@ void CommitForm::revertCurrentImpl() { auto selected = ui->tableView->currentIndex(); auto idx = model->index(selected.row(), 2); auto fileName = model->data(idx, Qt::DisplayRole).toString(); + + auto msgBox = QMessageBox(); + msgBox.setWindowTitle("Revert file"); + msgBox.setText(tr("Are you sure you want to revert this file?\n%1").arg(fileName)); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + msgBox.setIcon(QMessageBox::Icon::Question); + auto reply = msgBox.exec(); + if (reply != QMessageBox::Yes) { + return; + } + auto args = QStringList{"-C", repoRoot, "checkout", fileName}; auto [output, exitCode] = git->runGit(args); ui->gitOutput->setText(output); @@ -371,6 +388,18 @@ void CommitForm::revertSelectionImpl() { return; } + auto msgBox = QMessageBox(); + msgBox.setWindowTitle("Revert multiple files"); + msgBox.setText(tr("Are you sure you want to revert %1 files?").arg(checked.count())); + msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + msgBox.setDefaultButton(QMessageBox::No); + msgBox.setIcon(QMessageBox::Icon::Question); + auto reply = msgBox.exec(); + if (reply != QMessageBox::Yes) { + return; + } + + auto args = QStringList{"-C", repoRoot, "checkout"}; for (auto &c : std::as_const(checked)) { args.push_back(c.filename); @@ -382,3 +411,5 @@ void CommitForm::revertSelectionImpl() { updateGitStatus(); } } + +void CommitForm::commitImpl() {} diff --git a/src/plugins/git/CommitForm.hpp b/src/plugins/git/CommitForm.hpp index 317806e..9a3c9e9 100644 --- a/src/plugins/git/CommitForm.hpp +++ b/src/plugins/git/CommitForm.hpp @@ -27,6 +27,7 @@ class CommitForm : public QWidget, public qmdiClient { void newFileSelected(const QString &filename); void revertCurrentImpl(); void revertSelectionImpl(); + void commitImpl(); private: Ui::CommitForm *ui; From d19051cc01c673555e6c589aae65102d995be203 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Tue, 10 Feb 2026 00:26:21 +0200 Subject: [PATCH 13/22] Git/CommitForm: commit implementation I tested a simple commit on a dummy project, all seems to work. --- src/plugins/git/CommitForm.cpp | 62 ++++++++++++++++++++++++++++------ 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 0869fb4..386cb24 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -1,8 +1,10 @@ #include #include #include -#include #include +#include +#include +#include #include "CommitForm.hpp" #include "GitPlugin.hpp" @@ -20,12 +22,10 @@ struct GitStatusEntry { static auto parseGitStatus(QStringView statusOutput) -> QList { auto out = QList{}; - for (auto line : statusOutput.split('\n', Qt::SkipEmptyParts) | std::views::filter([](auto l) { return l.size() >= 3; })) { const auto x = line[0]; const auto y = line[1]; - out.append( {line.mid(3).trimmed().toString(), (x == '?' && y == '?') ? GitFileStatus::Untracked : (x == 'A' || y == 'A') ? GitFileStatus::Added @@ -38,6 +38,19 @@ static auto parseGitStatus(QStringView statusOutput) -> QList { return out; } +auto createTempFileWithContent(const QString &content) -> QString { + auto file = QTemporaryFile(); + // keep file after destruction + file.setAutoRemove(false); + if (!file.open()) { + return {}; + } + auto out = QTextStream(&file); + out << content; + file.close(); + return file.fileName(); +} + class GitStatusTableModel final : public QAbstractTableModel { // Q_OBJECT @@ -294,16 +307,13 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) }); connect(model, &QAbstractItemModel::modelReset, this, [this]() { ui->revertSelectedButton->setEnabled(false); }); - - connect(ui->selectAllButton, &QAbstractButton::clicked, this, [this]() { - model->setAllChecked(true); -/* ui->revertSelectedButton->setEnabled(true); -*/ }); + connect(ui->selectAllButton, &QAbstractButton::clicked, this, + [this]() { model->setAllChecked(true); }); connect(ui->selectNoneButton, &QAbstractButton::clicked, this, [this]() { model->setAllChecked(false); ui->revertSelectedButton->setEnabled(false); }); - + connect(ui->commitButton, &QAbstractButton::clicked, this, &CommitForm::commitImpl); updateGitStatus(); } @@ -399,7 +409,6 @@ void CommitForm::revertSelectionImpl() { return; } - auto args = QStringList{"-C", repoRoot, "checkout"}; for (auto &c : std::as_const(checked)) { args.push_back(c.filename); @@ -412,4 +421,35 @@ void CommitForm::revertSelectionImpl() { } } -void CommitForm::commitImpl() {} +void CommitForm::commitImpl() { + auto const &checked = model->checkedEntries(); + if (checked.isEmpty()) { + return; + } + + auto args = QStringList{"-C", repoRoot, "add"}; + for (auto const &c : checked) { + args.push_back(c.filename); + } + auto [output, exitCode] = git->runGit(args); + if (exitCode != 0) { + qDebug() << QString("ExitCode=%1, output=%2\ncommand=%3") + .arg(exitCode) + .arg(output) + .arg(QString("git ") + args.join(' ')); + return; + } + + auto commitLogFileName = createTempFileWithContent(ui->commitMessage->toPlainText()); + auto cleanup = qScopeGuard([&] { QFile::remove(commitLogFileName); }); + args = QStringList{"-C", repoRoot, "commit", "-F", commitLogFileName}; + std::tie(output, exitCode) = git->runGit(args); + if (exitCode != 0) { + qDebug() << QString("ExitCode=%1, output=%2\ncommand=%3") + .arg(exitCode) + .arg(output) + .arg(QString("git ") + args.join(' ')); + return; + } + this->deleteLater(); +} From 7550e7d64b24863993b19e0d29672987b45f1b72 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Tue, 10 Feb 2026 23:29:04 +0200 Subject: [PATCH 14/22] Meta: clang-format + code spell --- src/plugins/git/CommitForm.cpp | 6 +++--- src/widgets/qmdieditor.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 386cb24..a7ee502 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -231,8 +231,8 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) // 2. When double clicking a line in a diff, the code directly opens the // modified file. Instead we will need to modify the code, and somehow // catch this event in this class, and navigate to the file. - // 3. 3 Color layuout would be strech on small screens. I would like that - // on smaller "displays" the editor would be bellow the diff view, and + // 3. 3 Color layuout would be stretch on small screens. I would like that + // on smaller "displays" the editor would be below the diff view, and // on larger screen on the side. Qt provides no such layout. // Solution to this might be having 2 editors with shared document, and // on resize hide/show the revevant one. Other alternative - move it @@ -284,7 +284,7 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) &CommitForm::revertSelectionImpl); connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this](const QItemSelection &selected, const QItemSelection &deselected) { - qDebug() << "selection model cahnged"; + qDebug() << "selection model changed"; if (selected.indexes().size() == 0) { newFileSelected({}); return; diff --git a/src/widgets/qmdieditor.h b/src/widgets/qmdieditor.h index 82982af..67c1f46 100644 --- a/src/widgets/qmdieditor.h +++ b/src/widgets/qmdieditor.h @@ -182,7 +182,7 @@ class qmdiEditor : public QWidget, public qmdiClient { inline void foldTopLevel() const { textEditor->foldTopLevelBlocks(); } inline void setMinimapVisible(bool value) const { textEditor->setMinimapVisible(value); } void setReadOnly(bool b); - inline QPlainTextEdit* getEditor() const { return textEditor; } + inline QPlainTextEdit *getEditor() const { return textEditor; } inline void setHighlighter(const QString &languageId) { textEditor->setHighlighter(languageId); } From 219d27f96b715aec42b7fda1234139cdb97924f4 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Tue, 10 Feb 2026 23:41:19 +0200 Subject: [PATCH 15/22] CommitForm: git compilation undert older gcc Original code used ranges, which is not properly supported on Ubuntu 24.04. Use older code, which IMHO event looks nicer. --- src/plugins/git/CommitForm.cpp | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index a7ee502..75b7dae 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -20,20 +20,24 @@ struct GitStatusEntry { bool checked = false; }; -static auto parseGitStatus(QStringView statusOutput) -> QList { - auto out = QList{}; - for (auto line : statusOutput.split('\n', Qt::SkipEmptyParts) | - std::views::filter([](auto l) { return l.size() >= 3; })) { - const auto x = line[0]; - const auto y = line[1]; - out.append( - {line.mid(3).trimmed().toString(), (x == '?' && y == '?') ? GitFileStatus::Untracked - : (x == 'A' || y == 'A') ? GitFileStatus::Added - : (x == 'M' || y == 'M') ? GitFileStatus::Modified - : (x == 'D' || y == 'D') ? GitFileStatus::Deleted - : (x == 'R' || y == 'R') ? GitFileStatus::Renamed - : (x == 'C' || y == 'C') ? GitFileStatus::Copied - : GitFileStatus::Unknown}); +static auto parseGitStatus(QStringView statusOutput) -> QList +{ + auto out = QList(); + for (auto line : statusOutput.split('\n', Qt::SkipEmptyParts)) { + if (line.size() < 3) { + continue; + } + auto x = line[0]; + auto y = line[1]; + auto status = + (x == '?' && y == '?') ? GitFileStatus::Untracked : + (x == 'A' || y == 'A') ? GitFileStatus::Added : + (x == 'M' || y == 'M') ? GitFileStatus::Modified : + (x == 'D' || y == 'D') ? GitFileStatus::Deleted : + (x == 'R' || y == 'R') ? GitFileStatus::Renamed : + (x == 'C' || y == 'C') ? GitFileStatus::Copied : + GitFileStatus::Unknown; + out.append({ line.mid(3).trimmed().toString(), status }); } return out; } From c22c09a0b4110679f84d72a4aadb2d7a1fc68a7e Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Thu, 12 Feb 2026 19:08:28 +0200 Subject: [PATCH 16/22] clang-format --- src/plugins/git/CommitForm.cpp | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 75b7dae..4a73643 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -20,8 +20,7 @@ struct GitStatusEntry { bool checked = false; }; -static auto parseGitStatus(QStringView statusOutput) -> QList -{ +static auto parseGitStatus(QStringView statusOutput) -> QList { auto out = QList(); for (auto line : statusOutput.split('\n', Qt::SkipEmptyParts)) { if (line.size() < 3) { @@ -29,15 +28,14 @@ static auto parseGitStatus(QStringView statusOutput) -> QList } auto x = line[0]; auto y = line[1]; - auto status = - (x == '?' && y == '?') ? GitFileStatus::Untracked : - (x == 'A' || y == 'A') ? GitFileStatus::Added : - (x == 'M' || y == 'M') ? GitFileStatus::Modified : - (x == 'D' || y == 'D') ? GitFileStatus::Deleted : - (x == 'R' || y == 'R') ? GitFileStatus::Renamed : - (x == 'C' || y == 'C') ? GitFileStatus::Copied : - GitFileStatus::Unknown; - out.append({ line.mid(3).trimmed().toString(), status }); + auto status = (x == '?' && y == '?') ? GitFileStatus::Untracked + : (x == 'A' || y == 'A') ? GitFileStatus::Added + : (x == 'M' || y == 'M') ? GitFileStatus::Modified + : (x == 'D' || y == 'D') ? GitFileStatus::Deleted + : (x == 'R' || y == 'R') ? GitFileStatus::Renamed + : (x == 'C' || y == 'C') ? GitFileStatus::Copied + : GitFileStatus::Unknown; + out.append({line.mid(3).trimmed().toString(), status}); } return out; } From 62017f4842a66e8e16452e71c0d249b4dae6ccbf Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 14 Feb 2026 11:40:20 +0200 Subject: [PATCH 17/22] Git: fix log handlers At some point I messed up logs of file and project. Fix is easy, just use the full filename. Git will do the correct thing. --- src/plugins/git/CommitForm.cpp | 2 +- src/plugins/git/GitPlugin.cpp | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 4a73643..2e255fe 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -377,7 +377,7 @@ void CommitForm::revertCurrentImpl() { auto msgBox = QMessageBox(); msgBox.setWindowTitle("Revert file"); - msgBox.setText(tr("Are you sure you want to revert this file?\n%1").arg(fileName)); + msgBox.setText(tr("Are you sure you want to revert this file?\n%1").arg(fileName)); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); msgBox.setIcon(QMessageBox::Icon::Question); diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index 18851e0..65f1bf4 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -357,22 +357,17 @@ void GitPlugin::commitHandler() { return; } - auto repoRoot = QFileInfo(filename).absolutePath(); - repoRoot = detectRepoRoot(repoRoot); - qDebug() << "Current client" << filename << "at dir" << repoRoot; + auto repoRoot = detectRepoRoot(filename); if (repoRoot.isEmpty()) { qDebug() << "Filename is not in any git repo" << filename; return; } - // qDebug() << "Will commit in repo" << repoRoot; - auto commitForm = new CommitForm(repoRoot, this, manager); mdiServer->addClient(commitForm); } void GitPlugin::logHandler(GitLog log, const QString &filename) { - auto repoRoot = QFileInfo(filename).absolutePath(); - repoRoot = detectRepoRoot(repoRoot); + auto repoRoot = detectRepoRoot(filename); if (repoRoot.isEmpty()) { form->label->setText(tr("No commits or not a git repo")); form->diffBranchButton->setEnabled(true); @@ -498,8 +493,8 @@ QString GitPlugin::detectRepoRoot(const QString &filePath) { auto args = QStringList{"-C", dir, "rev-parse", "--show-toplevel"}; auto [output, exitCode] = runGit(args); if (exitCode != 0) { - qDebug() << "detectRepoRoot failed, with error" << exitCode << "output" << output - << "args:" << args; + qDebug() << "detectRepoRoot failed for file" << filePath << ", with error" << exitCode + << "output" << output << "args:" << args; return {}; } return output.trimmed(); From 85033b53449b585824690e3b82cd905e094dae4e Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 14 Feb 2026 16:35:20 +0200 Subject: [PATCH 18/22] GitPlugin: small refactor, remove the lambda - and use a proper slot --- src/plugins/git/GitPlugin.cpp | 57 +++++++++++++++++++---------------- src/plugins/git/GitPlugin.hpp | 1 + 2 files changed, 32 insertions(+), 26 deletions(-) diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index 65f1bf4..df82a94 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -14,19 +14,22 @@ #include #include -#include "CommitDelegate.hpp" -#include "CommitModel.hpp" -#include "GitPlugin.hpp" +#include + + #include "GlobalCommands.hpp" -#include "iplugin.h" -#include "plugins/git/CommitForm.hpp" -#include "plugins/git/CreateGitBranch.hpp" #include "ui_GitCommands.h" #include "ui_GitCommit.h" #include "widgets/AutoShrinkLabel.hpp" #include "widgets/BoldItemDelegate.hpp" #include "widgets/qmdieditor.h" +#include "plugins/git/CommitForm.hpp" +#include "plugins/git/CommitDelegate.hpp" +#include "plugins/git/CommitModel.hpp" +#include "plugins/git/CreateGitBranch.hpp" +#include "plugins/git/GitPlugin.hpp" + QString shortGitSha1(const QString &fullSha1, int length = 7) { if (length <= 0) { return QString(); @@ -366,6 +369,27 @@ void GitPlugin::commitHandler() { mdiServer->addClient(commitForm); } +void GitPlugin::commitDisplayHandler(const QModelIndex &mi) { + auto widget = static_cast(form->container->widget(0)); + auto manager = getManager(); + auto filename = mi.data().toString(); + auto [diff, exitCode] = runGit({"-C", getConfig().getGitLastDir(), "show", + widget->currentSha1, "--", filename}); + if (exitCode != 0) { + // TODO display this error + return; + } + auto shortSha1 = shortGitSha1(widget->currentSha1); + auto displayName = QString("%1-%2.diff").arg(shortSha1, filename); + CommandArgs args = { + {GlobalArguments::FileName, displayName}, + {GlobalArguments::Content, diff}, + {GlobalArguments::ReadOnly, true}, + {GlobalArguments::SourceDirectory, getConfig().getGitLastDir()}, + }; + manager->handleCommandAsync(GlobalCommands::DisplayText, args); +} + void GitPlugin::logHandler(GitLog log, const QString &filename) { auto repoRoot = detectRepoRoot(filename); if (repoRoot.isEmpty()) { @@ -420,30 +444,11 @@ void GitPlugin::on_gitCommitClicked(const QModelIndex &mi) { auto rawCommit = getRawCommit(sha1); auto const fullCommit = FullCommitInfo::parse(rawCommit); auto widget = static_cast(form->container->widget(0)); - if (!widget) { widget = new GitCommitDisplay(form->container); form->container->addWidget(widget); connect(widget->ui.commits, &QAbstractItemView::doubleClicked, this, - [this, widget](const QModelIndex &i) { - auto manager = getManager(); - auto filename = i.data().toString(); - auto [diff, exitCode] = runGit({"-C", getConfig().getGitLastDir(), "show", - widget->currentSha1, "--", filename}); - if (exitCode != 0) { - // TODO display this error - return; - } - auto shortSha1 = shortGitSha1(widget->currentSha1); - auto displayName = QString("%1-%2.diff").arg(shortSha1, filename); - CommandArgs args = { - {GlobalArguments::FileName, displayName}, - {GlobalArguments::Content, diff}, - {GlobalArguments::ReadOnly, true}, - {GlobalArguments::SourceDirectory, getConfig().getGitLastDir()}, - }; - manager->handleCommandAsync(GlobalCommands::DisplayText, args); - }); + &GitPlugin::commitDisplayHandler); } widget->currentSha1 = sha1; diff --git a/src/plugins/git/GitPlugin.hpp b/src/plugins/git/GitPlugin.hpp index 63c2ae2..a613569 100644 --- a/src/plugins/git/GitPlugin.hpp +++ b/src/plugins/git/GitPlugin.hpp @@ -45,6 +45,7 @@ class GitPlugin : public IPlugin { void diffBranchHandler(); void newBranchHandler(); void deleteBranchHandler(); + void commitDisplayHandler(const QModelIndex &mi); void commitHandler(); void logHandler(GitPlugin::GitLog log, const QString &filename); void on_gitCommitClicked(const QModelIndex &mi); From 4ba992bf4081af0beddf4abcc055db37cf19eecd Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 14 Feb 2026 18:46:20 +0200 Subject: [PATCH 19/22] Git/commit: display preview of files If this is a new (or deleted) file - try to display it (if its text). Honor the highlighter of said file. Implementation is not ideal, as we brake abstractions. FIXME is in some places. --- src/plugins/git/CommitForm.cpp | 95 +++++++++++++++++++++++++++------- src/plugins/git/CommitForm.hpp | 4 +- src/plugins/git/GitPlugin.cpp | 7 ++- 3 files changed, 82 insertions(+), 24 deletions(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 2e255fe..084f9dd 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -12,8 +12,6 @@ #include "ui_CommitForm.h" #include "widgets/qmdieditor.h" -enum class GitFileStatus { Modified, Added, Deleted, Renamed, Copied, Untracked, Unknown }; - struct GitStatusEntry { QString filename; GitFileStatus status; @@ -57,6 +55,7 @@ class GitStatusTableModel final : public QAbstractTableModel { // Q_OBJECT public: + enum Roles { StatusRole = Qt::UserRole + 1 }; explicit GitStatusTableModel(QObject *parent = nullptr); // Re-implementation rom QAbstractTableModel @@ -95,6 +94,9 @@ auto GitStatusTableModel::data(const QModelIndex &index, int role) const -> QVar return {}; } const auto &e = m_entries.at(index.row()); + if (role == StatusRole) { + return static_cast(e.status); + } if (index.column() == 0 && role == Qt::CheckStateRole) { return e.checked ? Qt::Checked : Qt::Unchecked; } @@ -196,14 +198,11 @@ void GitStatusTableModel::setAllChecked(bool checked) { if (m_entries.isEmpty()) { return; } - for (auto &e : m_entries) { e.checked = checked; } - - const QModelIndex topLeft = index(0, 0); - const QModelIndex bottomRight = index(rowCount() - 1, 0); - + auto topLeft = index(0, 0); + auto bottomRight = index(rowCount() - 1, 0); emit dataChanged(topLeft, bottomRight, {Qt::CheckStateRole}); } @@ -285,17 +284,18 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) connect(ui->revertSelectedButton, &QAbstractButton::clicked, this, &CommitForm::revertSelectionImpl); connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, - [this](const QItemSelection &selected, const QItemSelection &deselected) { + [this](const QItemSelection &selected, const QItemSelection &) { qDebug() << "selection model changed"; if (selected.indexes().size() == 0) { - newFileSelected({}); + newFileSelected({}, GitFileStatus::Unknown); return; } auto firstIndex = selected.indexes().first(); auto idx = model->index(firstIndex.row(), 2); auto fileName = model->data(idx, Qt::DisplayRole).toString(); - newFileSelected(fileName); - Q_UNUSED(deselected); + auto status = static_cast( + model->data(idx, GitStatusTableModel::StatusRole).toInt()); + newFileSelected(fileName, status); }); connect(model, &QAbstractItemModel::dataChanged, this, [this](const QModelIndex &, const QModelIndex &, const QList &roles) { @@ -344,27 +344,83 @@ void CommitForm::updateGitStatus() { } } -void CommitForm::newFileSelected(const QString &filename) { +void CommitForm::newFileSelected(const QString &filename, GitFileStatus status) { if (filename.isEmpty()) { ui->diffPreview->setPlainText(""); return; } - auto [output, exitCode] = git->runGit({"-C", repoRoot, "diff", filename}); - if (exitCode != 0) { - qDebug() << QString("git - code=%1, output=[%2]").arg(exitCode).arg(output); - ui->commitLogLabel->setText(""); - ui->diffPreview->setPlainText(output); - return; + auto output = QString(); + auto highlighter = QString{"diff.xml"}; + auto fullFilePath = repoRoot + "/" + filename; + switch (status) { + case GitFileStatus::Modified: { + auto [output2, exitCode] = git->runGit({"-C", repoRoot, "diff", filename}); + if (exitCode != 0) { + qDebug() << QString("git - code=%1, output=[%2]").arg(exitCode).arg(output2); + ui->commitLogLabel->setText(""); + ui->diffPreview->setPlainText(output); + return; + } + output = output2; + } + case GitFileStatus::Deleted: + break; + case GitFileStatus::Added: + case GitFileStatus::Renamed: + case GitFileStatus::Copied: + case GitFileStatus::Untracked: { + auto manager = git->getManager(); + auto plugin = manager->findPlugin("TextEditorPlugin"); + + auto p = dynamic_cast(plugin); + if (!p) { + qDebug() << "Cannot find the text editor plugin"; + break; + } + auto score = p->canOpenFile(fullFilePath); + if (score == 1) { + qDebug() << "Text editor plugin says this is not a text file" << score << fullFilePath; + break; + } + + auto file = QFile(fullFilePath); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << "Could not open file for reading" << fullFilePath; + break; + } + auto in = QTextStream(&file); + auto lineCount = 5000; + while (!in.atEnd() && lineCount >= 0) { + output += in.readLine(); + output += "\n"; + } + file.close(); + + auto langInfo = ::Qutepart::chooseLanguage({}, {}, filename); + if (langInfo.isValid()) { + highlighter = langInfo.id; + } + break; + } + default: + break; } + // FIXME: Note how we need to hijack the low level APIs of Qutepart + // to set the syntax highlighter. + // We need better abstractions, some IEditor, which can be an + // interface with has implementation as Qutepart of QSCintilla or + // something different completelly. ui->diffPreview->setPlainText(output); + // FIXME: this looks way too ugly, // Problem - the "editor" is not the correct widge // The UI expects a QPlainTextEdit, and we have Widget that includes a // QPlainTextEdit. if (auto editor = dynamic_cast(ui->diffPreview->parent()->parent())) { editor->updateInternalMappings(repoRoot); + editor->setHighlighter(highlighter); } else { qDebug() << "Double click on diff will not work"; } @@ -377,7 +433,8 @@ void CommitForm::revertCurrentImpl() { auto msgBox = QMessageBox(); msgBox.setWindowTitle("Revert file"); - msgBox.setText(tr("Are you sure you want to revert this file?\n%1").arg(fileName)); + msgBox.setText(tr("Are you sure you want to revert this file?

%1").arg(fileName)); + msgBox.setTextFormat(Qt::RichText); msgBox.setStandardButtons(QMessageBox::Yes | QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); msgBox.setIcon(QMessageBox::Icon::Question); diff --git a/src/plugins/git/CommitForm.hpp b/src/plugins/git/CommitForm.hpp index 9a3c9e9..c8b5efc 100644 --- a/src/plugins/git/CommitForm.hpp +++ b/src/plugins/git/CommitForm.hpp @@ -10,6 +10,8 @@ class CommitForm; class GitPlugin; class GitStatusTableModel; +enum class GitFileStatus { Modified, Added, Deleted, Renamed, Copied, Untracked, Unknown }; + class CommitForm : public QWidget, public qmdiClient { Q_OBJECT @@ -24,7 +26,7 @@ class CommitForm : public QWidget, public qmdiClient { public slots: void updateGitStatus(); - void newFileSelected(const QString &filename); + void newFileSelected(const QString &filename, GitFileStatus status); void revertCurrentImpl(); void revertSelectionImpl(); void commitImpl(); diff --git a/src/plugins/git/GitPlugin.cpp b/src/plugins/git/GitPlugin.cpp index df82a94..51db26f 100644 --- a/src/plugins/git/GitPlugin.cpp +++ b/src/plugins/git/GitPlugin.cpp @@ -16,7 +16,6 @@ #include - #include "GlobalCommands.hpp" #include "ui_GitCommands.h" #include "ui_GitCommit.h" @@ -24,8 +23,8 @@ #include "widgets/BoldItemDelegate.hpp" #include "widgets/qmdieditor.h" -#include "plugins/git/CommitForm.hpp" #include "plugins/git/CommitDelegate.hpp" +#include "plugins/git/CommitForm.hpp" #include "plugins/git/CommitModel.hpp" #include "plugins/git/CreateGitBranch.hpp" #include "plugins/git/GitPlugin.hpp" @@ -373,8 +372,8 @@ void GitPlugin::commitDisplayHandler(const QModelIndex &mi) { auto widget = static_cast(form->container->widget(0)); auto manager = getManager(); auto filename = mi.data().toString(); - auto [diff, exitCode] = runGit({"-C", getConfig().getGitLastDir(), "show", - widget->currentSha1, "--", filename}); + auto [diff, exitCode] = + runGit({"-C", getConfig().getGitLastDir(), "show", widget->currentSha1, "--", filename}); if (exitCode != 0) { // TODO display this error return; From effa01581a0250d918c90ad94c08112e7b0a7a46 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 14 Feb 2026 20:47:19 +0200 Subject: [PATCH 20/22] CommitForm.ui: fix warnings I keept seeing on the build console: ``` Warning: The name 'layoutWidget' (QWidget) is already in use, defaulting to 'layoutWidget2'. ``` Each time I create a layout, QtDesigner would host it inside a QWidget, which is not visible in the UI. The solution is to edit the XML by hand. Now those logs are gone. --- src/plugins/git/CommitForm.ui | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugins/git/CommitForm.ui b/src/plugins/git/CommitForm.ui index a77b382..dde3971 100644 --- a/src/plugins/git/CommitForm.ui +++ b/src/plugins/git/CommitForm.ui @@ -19,7 +19,7 @@ Qt::Orientation::Horizontal - + @@ -64,7 +64,7 @@ - + @@ -106,7 +106,7 @@ - + From 5ceec30de79090053d52c631ef82aaeda11377d5 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 14 Feb 2026 21:15:50 +0200 Subject: [PATCH 21/22] Git/CommitForm: use editor font Seems like all git commit forms are in monospaced font. Lets fix this. In a future iteration will need to do more cleanups - and use an editor with markdown style (?) or something more dedicated. I know that for example, the first line should not be more than 75 chars (that is what is the linux kernel use). (also - commit message is not saved in state, but this is another problem I will tackle later on) --- src/plugins/git/CommitForm.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index 084f9dd..e7a520b 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -263,6 +263,11 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) layout->replaceWidget(ui->diffPreview, e); ui->diffPreview->deleteLater(); ui->diffPreview = e->getEditor(); + + // FIXME: The diff-preview widget has the correct font + // configuration if we would create the widget from the + // plugin - instead we need to do this very ugly hack. + ui->commitMessage->setFont(e->getEditor()->font()); } } } @@ -285,7 +290,6 @@ CommitForm::CommitForm(const QString &dir, GitPlugin *plugin, QWidget *parent) &CommitForm::revertSelectionImpl); connect(ui->tableView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this](const QItemSelection &selected, const QItemSelection &) { - qDebug() << "selection model changed"; if (selected.indexes().size() == 0) { newFileSelected({}, GitFileStatus::Unknown); return; From 66c74dccdb50f9961f5edad8e301c314b0e32ad7 Mon Sep 17 00:00:00 2001 From: Diego Iastrubni Date: Sat, 14 Feb 2026 21:26:05 +0200 Subject: [PATCH 22/22] Code spell --- src/plugins/git/CommitForm.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugins/git/CommitForm.cpp b/src/plugins/git/CommitForm.cpp index e7a520b..5b5d2ff 100644 --- a/src/plugins/git/CommitForm.cpp +++ b/src/plugins/git/CommitForm.cpp @@ -415,7 +415,7 @@ void CommitForm::newFileSelected(const QString &filename, GitFileStatus status) // to set the syntax highlighter. // We need better abstractions, some IEditor, which can be an // interface with has implementation as Qutepart of QSCintilla or - // something different completelly. + // something different completely. ui->diffPreview->setPlainText(output); // FIXME: this looks way too ugly,