File indexing completed on 2024-05-12 04:37:47

0001 /*
0002     SPDX-FileCopyrightText: 2008 David Nolden <david.nolden.kdevelop@art-master.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-only
0005 */
0006 
0007 #ifndef KDEVPLATFORM_DOCUMENTCHANGESET_H
0008 #define KDEVPLATFORM_DOCUMENTCHANGESET_H
0009 
0010 #include <language/languageexport.h>
0011 
0012 #include <serialization/indexedstring.h>
0013 
0014 #include <KTextEditor/Range>
0015 
0016 #include <QExplicitlySharedDataPointer>
0017 #include <QUrl>
0018 
0019 namespace KDevelop {
0020 class DocumentChangeSetPrivate;
0021 
0022 class KDEVPLATFORMLANGUAGE_EXPORT DocumentChange
0023     : public QSharedData
0024 {
0025 public:
0026 
0027     DocumentChange(const IndexedString& document, const KTextEditor::Range& range, const QString& oldText,
0028                    const QString& newText) :
0029         m_document(document)
0030         , m_range(range)
0031         , m_oldText(oldText)
0032         , m_newText(newText)
0033         , m_ignoreOldText(false)
0034     {
0035         //Clean the URL, so we don't get the same file be stored as a different one
0036         QUrl url = m_document.toUrl();
0037         m_document = IndexedString(url.adjusted(QUrl::NormalizePathSegments));
0038     }
0039 
0040     IndexedString m_document;
0041     KTextEditor::Range m_range;
0042     QString m_oldText;
0043     QString m_newText;
0044     bool m_ignoreOldText; //Set this to disable the verification of m_oldText. This can be used to overwrite arbitrary text, but is dangerous!
0045 };
0046 
0047 using DocumentChangePointer = QExplicitlySharedDataPointer<DocumentChange>;
0048 
0049 /**
0050  * Object representing an arbitrary set of changes to an arbitrary set of files that can be applied atomically.
0051  */
0052 class KDEVPLATFORMLANGUAGE_EXPORT DocumentChangeSet
0053 {
0054 public:
0055     DocumentChangeSet();
0056     ~DocumentChangeSet();
0057     DocumentChangeSet(const DocumentChangeSet& rhs);
0058     DocumentChangeSet& operator=(const DocumentChangeSet& rhs);
0059 
0060     //Returns true on success
0061     class ChangeResult
0062     {
0063 public:
0064         explicit ChangeResult(const QString& failureReason,
0065                               const DocumentChangePointer& reasonChange = DocumentChangePointer())
0066             : ChangeResult(failureReason, reasonChange, false) {}
0067 
0068         static ChangeResult successfulResult()
0069         {
0070             return ChangeResult({}, {}, true);
0071         }
0072 
0073         operator bool() const
0074         {
0075             return m_success;
0076         }
0077 
0078         /// Reason why the change failed
0079         QString m_failureReason;
0080         /// Specific change that caused the problem (might be 0)
0081         DocumentChangePointer m_reasonChange;
0082 
0083         bool m_success;
0084 
0085 private:
0086         explicit ChangeResult(const QString& failureReason, const DocumentChangePointer& reasonChange, bool success)
0087             : m_failureReason(failureReason)
0088             , m_reasonChange(reasonChange)
0089             , m_success(success)
0090         {}
0091     };
0092 
0093     /// Add an individual local change to this change-set.
0094     ChangeResult addChange(const DocumentChange& change);
0095     ChangeResult addChange(const DocumentChangePointer& change);
0096 
0097     ///given a file @p oldFile, rename it to the @p newname
0098     ChangeResult addDocumentRenameChange(const IndexedString& oldFile, const IndexedString& newname);
0099 
0100     enum ReplacementPolicy {
0101         IgnoreFailedChange,///If this is given, all changes that could not be applied are simply ignored
0102         WarnOnFailedChange,///If this is given to applyAllChanges, a warning is given when a change could not be applied,
0103         ///but following changes are applied, and success is returned.
0104         StopOnFailedChange ///If this is given to applyAllChanges, then all replacements are reverted and an error returned on problems (default)
0105     };
0106 
0107     ///@param policy What should be done when a change could not be applied?
0108     void setReplacementPolicy(ReplacementPolicy policy);
0109 
0110     enum FormatPolicy {
0111         NoAutoFormat, ///If this option is given, no automatic formatting is applied
0112         AutoFormatChanges,      ///If this option is given, all changes are automatically reformatted using the formatter plugin for the mime type (default)
0113         AutoFormatChangesKeepIndentation      ///Same as AutoFormatChanges, except that the indentation of inserted lines is kept equal
0114     };
0115 
0116     ///@param policy How the changed text should be formatted. The default is AutoFormatChanges.
0117     void setFormatPolicy(FormatPolicy policy);
0118 
0119     enum DUChainUpdateHandling {
0120         NoUpdate,       ///No updates will be scheduled
0121         SimpleUpdate ///The changed documents will be added to the background parser, plus all documents that are currently open and recursively import those documents (default)
0122         //FullUpdate       ///All documents in all open projects that recursively import any of the changed documents will be updated
0123     };
0124 
0125     ///@param policy Whether a duchain update should be triggered for all affected documents
0126     void setUpdateHandling(DUChainUpdateHandling policy);
0127 
0128     enum ActivationPolicy {
0129         Activate,           ///The affected files will be activated
0130         DoNotActivate  ///The affected files will not be activated (default)
0131     };
0132 
0133     ///@param policy Whether the affected documents should be activated when the change is applied
0134     void setActivationPolicy(ActivationPolicy policy);
0135 
0136     /// Apply all the changes registered in this changeset to the actual files
0137     ChangeResult applyAllChanges();
0138 
0139 private:
0140     const QScopedPointer<class DocumentChangeSetPrivate> d_ptr;
0141     Q_DECLARE_PRIVATE(DocumentChangeSet)
0142 };
0143 }
0144 
0145 #endif