| 
									
										
										
										
											2022-08-19 15:59:36 +02:00
										 |  |  | // 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
 | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "virtualfilesystemoverlay.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <coreplugin/documentmanager.h>
 | 
					
						
							| 
									
										
										
										
											2020-08-25 06:18:26 +02:00
										 |  |  | #include <coreplugin/editormanager/documentmodel.h>
 | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  | #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) | 
					
						
							| 
									
										
										
										
											2021-07-01 09:58:48 +02:00
										 |  |  |     , m_overlayFilePath(m_root.filePath("vfso.yaml")) | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  | { } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void VirtualFileSystemOverlay::update() | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2021-07-01 08:59:32 +02:00
										 |  |  |     overlayFilePath().removeRecursively(); | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  |     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(); | 
					
						
							| 
									
										
										
										
											2020-11-17 00:23:17 +01:00
										 |  |  |     QHash<Core::IDocument *, AutoSavedPath> newSaved; | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  |     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()) { | 
					
						
							| 
									
										
										
										
											2021-07-01 08:59:32 +02:00
										 |  |  |             saved.path.removeRecursively(); | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  |             saved.revision = document->document()->revision(); | 
					
						
							|  |  |  |             QString error; | 
					
						
							| 
									
										
										
										
											2021-07-01 09:58:48 +02:00
										 |  |  |             saved.path = m_root.filePath(doc->filePath().fileName() + ".auto"); | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  |             while (saved.path.exists()) | 
					
						
							|  |  |  |                 saved.path = saved.path + ".1"; | 
					
						
							| 
									
										
										
										
											2021-05-18 13:55:23 +02:00
										 |  |  |             if (!doc->save(&error, saved.path, true)) { | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  |                 qCDebug(LOG) << error; | 
					
						
							|  |  |  |                 continue; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         newSaved[doc] = saved; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-10-07 14:46:06 +02:00
										 |  |  |     for (const AutoSavedPath &path : std::as_const(m_saved)) { | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  |         QString error; | 
					
						
							| 
									
										
										
										
											2021-07-01 08:59:32 +02:00
										 |  |  |         if (!path.path.removeRecursively(&error)) | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  |             qCDebug(LOG) << error; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     m_saved = newSaved; | 
					
						
							| 
									
										
										
										
											2020-08-25 06:18:26 +02:00
										 |  |  |     m_mapping.clear(); | 
					
						
							|  |  |  |     for (auto it = m_saved.constBegin(), end = m_saved.constEnd(); it != end; ++it) | 
					
						
							|  |  |  |         m_mapping[it.value().path] = it.key()->filePath(); | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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; | 
					
						
							| 
									
										
										
										
											2022-10-07 14:46:06 +02:00
										 |  |  |         for (auto doc : std::as_const(documents)) | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  |             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; } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-25 06:18:26 +02:00
										 |  |  | Utils::FilePath VirtualFileSystemOverlay::autoSavedFilePath(Core::IDocument *doc) | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     auto it = m_saved.find(doc); | 
					
						
							|  |  |  |     if (it != m_saved.end()) | 
					
						
							|  |  |  |         return it.value().path; | 
					
						
							|  |  |  |     return doc->filePath(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-25 06:18:26 +02:00
										 |  |  | Utils::FilePath VirtualFileSystemOverlay::originalFilePath(const Utils::FilePath &file) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return m_mapping.value(file, file); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-22 14:52:06 +02:00
										 |  |  | } // namespace Internal
 | 
					
						
							|  |  |  | } // namespace ClangTools
 |