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

0001 /* This file is part of the KDE project
0002    SPDX-FileCopyrightText: 2021 Méven Car <meven.car@kdemail.net>
0003 
0004    SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "katestashmanager.h"
0008 
0009 #include "katedebug.h"
0010 
0011 #include "kateapp.h"
0012 #include "kateviewmanager.h"
0013 
0014 #include <QDir>
0015 #include <QFile>
0016 #include <QStringDecoder>
0017 #include <QUrl>
0018 
0019 KateStashManager::KateStashManager(QObject *parent)
0020     : QObject(parent)
0021 {
0022 }
0023 
0024 void KateStashManager::clearStashForSession(const KateSession::Ptr session)
0025 {
0026     const QString appDataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
0027     QDir dir(appDataPath);
0028     if (dir.exists(QStringLiteral("stash"))) {
0029         dir.cd(QStringLiteral("stash"));
0030         const QString sessionName = session->name();
0031         if (dir.exists(sessionName)) {
0032             dir.cd(sessionName);
0033             dir.removeRecursively();
0034         }
0035     }
0036 }
0037 
0038 void KateStashManager::stashDocuments(KConfig *config, const QList<KTextEditor::Document *> &documents) const
0039 {
0040     if (!canStash()) {
0041         return;
0042     }
0043 
0044     // prepare stash directory
0045     const QString appDataPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
0046     QDir dir(appDataPath);
0047     dir.mkdir(QStringLiteral("stash"));
0048     dir.cd(QStringLiteral("stash"));
0049 
0050     const QString sessionName = KateApp::self()->sessionManager()->activeSession()->name();
0051     dir.mkdir(sessionName);
0052     dir.cd(sessionName);
0053 
0054     int i = 0;
0055     for (KTextEditor::Document *doc : documents) {
0056         // stash the file content
0057         if (doc->isModified()) {
0058             const QString entryName = QStringLiteral("Document %1").arg(i);
0059             KConfigGroup cg(config, entryName);
0060             stashDocument(doc, entryName, cg, dir.path());
0061         }
0062 
0063         i++;
0064     }
0065 }
0066 
0067 bool KateStashManager::willStashDoc(KTextEditor::Document *doc) const
0068 {
0069     Q_ASSERT(canStash());
0070 
0071     if (doc->isEmpty()) {
0072         return false;
0073     }
0074     if (doc->url().isEmpty()) {
0075         return m_stashNewUnsavedFiles;
0076     }
0077     if (doc->isModified() && doc->url().isLocalFile()) {
0078         const QString path = doc->url().toLocalFile();
0079         if (path.startsWith(QDir::tempPath())) {
0080             return false; // inside tmp resource, do not stash
0081         }
0082         return m_stashUnsavedChanges;
0083     }
0084     return false;
0085 }
0086 
0087 void KateStashManager::stashDocument(KTextEditor::Document *doc, const QString &stashfileName, KConfigGroup &kconfig, const QString &path) const
0088 {
0089     if (!willStashDoc(doc)) {
0090         return;
0091     }
0092     // Stash changes
0093     QString stashedFile = path + QStringLiteral("/") + stashfileName;
0094 
0095     // save the current document changes to stash
0096     if (!doc->saveAs(QUrl::fromLocalFile(stashedFile))) {
0097         qCWarning(LOG_KATE) << "Could not write to stash file" << stashedFile;
0098         return;
0099     }
0100 
0101     // write stash metadata to config
0102     kconfig.writeEntry("stashedFile", stashedFile);
0103     if (doc->url().isValid()) {
0104         // save checksum for already-saved documents
0105         kconfig.writeEntry("checksum", doc->checksum());
0106     }
0107 
0108     kconfig.sync();
0109 }
0110 
0111 bool KateStashManager::canStash() const
0112 {
0113     const auto activeSession = KateApp::self()->sessionManager()->activeSession();
0114     return activeSession && !activeSession->isAnonymous() && !activeSession->name().isEmpty();
0115 }
0116 
0117 void KateStashManager::popDocument(KTextEditor::Document *doc, const KConfigGroup &kconfig)
0118 {
0119     if (!(kconfig.hasKey("stashedFile"))) {
0120         return;
0121     }
0122     qCDebug(LOG_KATE) << "popping stashed document" << doc->url();
0123 
0124     // read metadata
0125     const auto stashedFile = kconfig.readEntry("stashedFile");
0126     const auto url = QUrl(kconfig.readEntry("URL"));
0127 
0128     bool checksumOk = true;
0129     if (url.isValid()) {
0130         const auto sum = kconfig.readEntry(QStringLiteral("checksum")).toLatin1().constData();
0131         checksumOk = sum != doc->checksum();
0132     }
0133 
0134     if (checksumOk) {
0135         // open file with stashed content
0136         QFile input(stashedFile);
0137         input.open(QIODevice::ReadOnly);
0138 
0139         auto decoder = QStringDecoder(kconfig.readEntry("Encoding").toUtf8().constData());
0140         QString text = decoder.isValid() ? decoder.decode(input.readAll()) : QString::fromLocal8Bit(input.readAll());
0141 
0142         // normalize line endings, to e.g. catch issues with \r\n on Windows
0143         text.replace(QRegularExpression(QStringLiteral("\r\n?")), QStringLiteral("\n"));
0144 
0145         doc->setText(text);
0146 
0147         // clean stashed file
0148         if (!input.remove()) {
0149             qCWarning(LOG_KATE) << "Could not remove stash file" << stashedFile;
0150         }
0151     }
0152 }
0153 
0154 #include "moc_katestashmanager.cpp"