aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/clangtools/virtualfilesystemoverlay.cpp
blob: 923f7d903ba8d05ec8066eab76155431bfc27d21 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Copyright (C) 2020 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0

#include "virtualfilesystemoverlay.h"

#include <coreplugin/documentmanager.h>
#include <coreplugin/editormanager/documentmodel.h>
#include <texteditor/textdocument.h>

#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QLoggingCategory>
#include <QTextDocument>

static Q_LOGGING_CATEGORY(LOG, "qtc.clangtools.vfso", QtWarningMsg)

namespace ClangTools {
namespace Internal {

VirtualFileSystemOverlay::VirtualFileSystemOverlay(const QString &rootPattern)
    : m_root(rootPattern)
    , m_overlayFilePath(m_root.filePath("vfso.yaml"))
{ }

void VirtualFileSystemOverlay::update()
{
    overlayFilePath().removeRecursively();
    QFile overlayFile(m_overlayFilePath.toString());
    if (!overlayFile.open(QFile::ReadWrite))
        return;
    std::map<Utils::FilePath, QList<Core::IDocument *>> documentRoots;
    const QList<Core::IDocument *> &modifiedDocuments = Core::DocumentManager::modifiedDocuments();
    QHash<Core::IDocument *, AutoSavedPath> newSaved;
    for (Core::IDocument *doc : modifiedDocuments) {
        auto document = qobject_cast<TextEditor::TextDocument *>(doc);
        if (!document)
            continue;
        documentRoots[doc->filePath().absolutePath()] << doc;
        AutoSavedPath saved = m_saved.take(document);
        if (saved.revision != document->document()->revision()) {
            saved.path.removeRecursively();
            saved.revision = document->document()->revision();
            QString error;
            saved.path = m_root.filePath(doc->filePath().fileName() + ".auto");
            while (saved.path.exists())
                saved.path = saved.path + ".1";
            if (!doc->save(&error, saved.path, true)) {
                qCDebug(LOG) << error;
                continue;
            }
        }
        newSaved[doc] = saved;
    }

    for (const AutoSavedPath &path : qAsConst(m_saved)) {
        QString error;
        if (!path.path.removeRecursively(&error))
            qCDebug(LOG) << error;
    }
    m_saved = newSaved;
    m_mapping.clear();
    for (auto it = m_saved.constBegin(), end = m_saved.constEnd(); it != end; ++it)
        m_mapping[it.value().path] = it.key()->filePath();

    auto toContent = [this](Core::IDocument *document) {
        QJsonObject content;
        content["name"] = document->filePath().fileName();
        content["type"] = "file";
        content["external-contents"] = m_saved[document].path.toUserOutput();
        return content;
    };

    QJsonObject main;
    main["version"] = 0;
    QJsonArray jsonRoots;
    for (auto [root, documents] : documentRoots) {
        QJsonObject jsonRoot;
        jsonRoot["type"] = "directory";
        jsonRoot["name"] = root.toUserOutput();
        QJsonArray contents;
        for (auto doc : qAsConst(documents))
            contents << toContent(doc);
        jsonRoot["contents"] = contents;
        jsonRoots << jsonRoot;
    }
    main["roots"] = jsonRoots;

    QJsonDocument overlay(main);
    if (!overlayFile.write(overlay.toJson(QJsonDocument::Compact)))
        qCDebug(LOG) << "failed to write vfso to " << m_overlayFilePath;
    overlayFile.close();
}

Utils::FilePath VirtualFileSystemOverlay::overlayFilePath() { return m_overlayFilePath; }

Utils::FilePath VirtualFileSystemOverlay::autoSavedFilePath(Core::IDocument *doc)
{
    auto it = m_saved.find(doc);
    if (it != m_saved.end())
        return it.value().path;
    return doc->filePath();
}

Utils::FilePath VirtualFileSystemOverlay::originalFilePath(const Utils::FilePath &file)
{
    return m_mapping.value(file, file);
}

} // namespace Internal
} // namespace ClangTools