File indexing completed on 2024-04-28 05:49:10

0001 /*
0002     SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 #include "stashdialog.h"
0007 #include "gitwidget.h"
0008 #include "hostprocess.h"
0009 
0010 #include <QProcess>
0011 #include <QTreeView>
0012 #include <QWidget>
0013 
0014 #include <KTextEditor/View>
0015 
0016 #include <KLocalizedString>
0017 
0018 #include <drawing_utils.h>
0019 
0020 #include <gitprocess.h>
0021 
0022 StashDialog::StashDialog(QWidget *parent, QWidget *window, const QString &gitPath)
0023     : HUDDialog(parent, window)
0024     , m_gitPath(gitPath)
0025 {
0026 }
0027 
0028 void StashDialog::openDialog(StashMode m)
0029 {
0030     setStringList({});
0031 
0032     switch (m) {
0033     case StashMode::Stash:
0034     case StashMode::StashKeepIndex:
0035     case StashMode::StashUntrackIncluded:
0036         m_lineEdit.setPlaceholderText(i18n("Stash message (optional). Enter to confirm, Esc to leave."));
0037         m_currentMode = m;
0038         break;
0039     case StashMode::StashPop:
0040     case StashMode::StashDrop:
0041     case StashMode::StashApply:
0042     case StashMode::ShowStashContent:
0043         m_lineEdit.setPlaceholderText(i18n("Type to filter, Enter to pop stash, Esc to leave."));
0044         m_currentMode = m;
0045         getStashList();
0046         break;
0047     case StashMode::StashApplyLast:
0048         applyStash({});
0049         return;
0050     case StashMode::StashPopLast:
0051         popStash({});
0052         return;
0053     default:
0054         return;
0055     }
0056 
0057     // trigger reselect first
0058     m_lineEdit.textChanged(QString());
0059     exec();
0060 }
0061 
0062 static QString getStashIndex(const QModelIndex &index)
0063 {
0064     QString s = index.data().toString();
0065     if (s.isEmpty() || !s.startsWith(QStringLiteral("stash@{"))) {
0066         return {};
0067     }
0068     static QRegularExpression re(QStringLiteral("stash@{(.*)}"));
0069     const auto match = re.match(s);
0070     if (!match.hasMatch())
0071         return {};
0072     return match.captured(1);
0073 }
0074 
0075 void StashDialog::slotReturnPressed(const QModelIndex &index)
0076 {
0077     switch (m_currentMode) {
0078     case StashMode::Stash:
0079         stash(false, false);
0080         break;
0081     case StashMode::StashKeepIndex:
0082         stash(true, false);
0083         break;
0084     case StashMode::StashUntrackIncluded:
0085         stash(false, true);
0086         break;
0087     default:
0088         break;
0089     }
0090 
0091     auto stashIndex = getStashIndex(index);
0092     if (stashIndex.isEmpty())
0093         return;
0094 
0095     switch (m_currentMode) {
0096     case StashMode::StashApply:
0097         applyStash(stashIndex);
0098         break;
0099     case StashMode::StashPop:
0100         popStash(stashIndex);
0101         break;
0102     case StashMode::StashDrop:
0103         dropStash(stashIndex);
0104         break;
0105     case StashMode::ShowStashContent:
0106         showStash(stashIndex);
0107         break;
0108     default:
0109         break;
0110     }
0111 
0112     hide();
0113 }
0114 
0115 QProcess *StashDialog::gitp(const QStringList &arguments)
0116 {
0117     auto git = new QProcess(this);
0118     setupGitProcess(*git, m_gitPath, arguments);
0119     return git;
0120 }
0121 
0122 void StashDialog::stash(bool keepIndex, bool includeUntracked)
0123 {
0124     QStringList args{QStringLiteral("stash"), QStringLiteral("-q")};
0125 
0126     if (keepIndex) {
0127         args.append(QStringLiteral("--keep-index"));
0128     }
0129     if (includeUntracked) {
0130         args.append(QStringLiteral("-u"));
0131     }
0132 
0133     if (!m_lineEdit.text().isEmpty()) {
0134         args.append(QStringLiteral("-m"));
0135         args.append(m_lineEdit.text());
0136     }
0137 
0138     auto git = gitp(args);
0139     connect(git, &QProcess::finished, this, [this, git](int exitCode, QProcess::ExitStatus es) {
0140         if (es != QProcess::NormalExit || exitCode != 0) {
0141             qWarning() << git->errorString();
0142             Q_EMIT message(i18n("Failed to stash changes %1", QString::fromUtf8(git->readAllStandardError())), true);
0143         } else {
0144             Q_EMIT message(i18n("Changes stashed successfully."), false);
0145         }
0146         Q_EMIT done();
0147         git->deleteLater();
0148     });
0149     startHostProcess(*git, QProcess::ReadOnly);
0150 }
0151 
0152 void StashDialog::getStashList()
0153 {
0154     auto git = gitp({QStringLiteral("stash"), QStringLiteral("list")});
0155     startHostProcess(*git, QProcess::ReadOnly);
0156 
0157     QStringList stashList;
0158     if (git->waitForStarted() && git->waitForFinished(-1)) {
0159         if (git->exitStatus() == QProcess::NormalExit && git->exitCode() == 0) {
0160             stashList = QString::fromUtf8(git->readAllStandardOutput()).split(QLatin1Char('\n'));
0161             setStringList(stashList);
0162         } else {
0163             Q_EMIT message(i18n("Failed to get stash list. Error: ") + QString::fromUtf8(git->readAll()), true);
0164         }
0165     }
0166 }
0167 
0168 void StashDialog::popStash(const QString &index, const QString &command)
0169 {
0170     QStringList args{QStringLiteral("stash"), command};
0171     if (!index.isEmpty()) {
0172         args.append(index);
0173     }
0174     auto git = gitp(args);
0175 
0176     connect(git, &QProcess::finished, this, [this, command, git](int exitCode, QProcess::ExitStatus es) {
0177         if (es != QProcess::NormalExit || exitCode != 0) {
0178             if (command == QLatin1String("apply")) {
0179                 Q_EMIT message(i18n("Failed to apply stash. Error: ") + QString::fromUtf8(git->readAll()), true);
0180             } else if (command == QLatin1String("drop")) {
0181                 Q_EMIT message(i18n("Failed to drop stash. Error: ") + QString::fromUtf8(git->readAll()), true);
0182             } else {
0183                 Q_EMIT message(i18n("Failed to pop stash. Error: ") + QString::fromUtf8(git->readAll()), true);
0184             }
0185         } else {
0186             if (command == QLatin1String("apply")) {
0187                 Q_EMIT message(i18n("Stash applied successfully."), false);
0188             } else if (command == QLatin1String("drop")) {
0189                 Q_EMIT message(i18n("Stash dropped successfully."), false);
0190             } else {
0191                 Q_EMIT message(i18n("Stash popped successfully."), false);
0192             }
0193         }
0194         Q_EMIT done();
0195         git->deleteLater();
0196     });
0197     startHostProcess(*git, QProcess::ReadOnly);
0198 }
0199 
0200 void StashDialog::applyStash(const QString &index)
0201 {
0202     popStash(index, QStringLiteral("apply"));
0203 }
0204 
0205 void StashDialog::dropStash(const QString &index)
0206 {
0207     popStash(index, QStringLiteral("drop"));
0208 }
0209 
0210 void StashDialog::showStash(const QString &index)
0211 {
0212     if (index.isEmpty()) {
0213         return;
0214     }
0215 
0216     auto git = gitp({QStringLiteral("stash"), QStringLiteral("show"), QStringLiteral("-p"), index});
0217 
0218     connect(git, &QProcess::finished, this, [this, git](int exitCode, QProcess::ExitStatus es) {
0219         if (es != QProcess::NormalExit || exitCode != 0) {
0220             Q_EMIT message(i18n("Show stash failed. Error: ") + QString::fromUtf8(git->readAll()), true);
0221         } else {
0222             Q_EMIT showStashDiff(git->readAllStandardOutput());
0223         }
0224         Q_EMIT done();
0225         git->deleteLater();
0226     });
0227 
0228     startHostProcess(*git, QProcess::ReadOnly);
0229 }
0230 
0231 #include "moc_stashdialog.cpp"