File indexing completed on 2024-12-08 11:06:05
0001 // clang-format off 0002 /* 0003 * KDiff3 - Text Diff And Merge Tool 0004 * 0005 * SPDX-FileCopyrightText: 2002-2011 Joachim Eibl, joachim.eibl at gmx.de 0006 * SPDX-FileCopyrightText: 2018-2020 Michael Reeves reeves.87@gmail.com 0007 * SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 // clang-format on 0010 0011 #ifndef MERGEEDITLINE_H 0012 #define MERGEEDITLINE_H 0013 0014 #include "diff.h" 0015 #include "LineRef.h" 0016 0017 #include <memory> 0018 0019 #include <QString> 0020 0021 using MergeEditLineList = std::list<class MergeEditLine>; 0022 0023 class MergeEditLine 0024 { 0025 public: 0026 explicit MergeEditLine(const Diff3LineList::const_iterator& i, e_SrcSelector src = e_SrcSelector::None) 0027 { 0028 m_id3l = i; 0029 mSrc = src; 0030 mLineRemoved = false; 0031 mChanged = false; 0032 } 0033 0034 void setConflict() 0035 { 0036 mSrc = e_SrcSelector::None; 0037 mLineRemoved = false; 0038 mChanged = false; 0039 mStr = QString(); 0040 } 0041 [[nodiscard]] inline bool isConflict() const { return mSrc == e_SrcSelector::None && !mLineRemoved && !mChanged; } 0042 0043 void setRemoved(e_SrcSelector src = e_SrcSelector::None) 0044 { 0045 mSrc = src; 0046 mLineRemoved = true; 0047 mStr = QString(); 0048 mChanged = (src == e_SrcSelector::None); 0049 } 0050 [[nodiscard]] inline bool isRemoved() const { return mLineRemoved; } 0051 0052 [[nodiscard]] inline bool isEditableText() const { return !isConflict(); } 0053 0054 void setString(const QString& s) 0055 { 0056 mStr = s; 0057 mLineRemoved = false; 0058 mSrc = e_SrcSelector::None; 0059 mChanged = true; 0060 } 0061 [[nodiscard]] QString getString(const std::shared_ptr<const LineDataVector>& pLineDataA, const std::shared_ptr<const LineDataVector>& pLineDataB, const std::shared_ptr<const LineDataVector>& pLineDataC) const; 0062 [[nodiscard]] inline bool isModified() const { return mChanged; } 0063 0064 void setSource(e_SrcSelector src, bool bLineRemoved) 0065 { 0066 mSrc = src; 0067 mLineRemoved = bLineRemoved; 0068 if(bLineRemoved && mSrc == e_SrcSelector::None) 0069 mChanged = true; 0070 else if(mSrc != e_SrcSelector::None) 0071 { 0072 mChanged = false; 0073 mStr = u8""; 0074 } 0075 } 0076 0077 [[nodiscard]] inline e_SrcSelector src() const { return mSrc; } 0078 [[nodiscard]] inline Diff3LineList::const_iterator id3l() const { return m_id3l; } 0079 0080 private: 0081 Diff3LineList::const_iterator m_id3l; 0082 e_SrcSelector mSrc; // 1, 2 or 3 for A, B or C respectively, or 0 when line is from neither source. 0083 QString mStr; // String when modified by user or null-string when orig data is used. 0084 bool mLineRemoved; 0085 bool mChanged; 0086 }; 0087 0088 class MergeBlock 0089 { 0090 private: 0091 friend class MergeBlockList; 0092 0093 Diff3LineList::const_iterator mId3l; 0094 LineType d3lLineIdx = -1; // Needed to show the correct window pos. 0095 LineType srcRangeLength = 0; // how many src-lines have these properties 0096 e_MergeDetails mergeDetails = e_MergeDetails::eDefault; 0097 bool bConflict = false; 0098 bool bWhiteSpaceConflict = false; 0099 bool bDelta = false; 0100 e_SrcSelector srcSelect = e_SrcSelector::None; 0101 MergeEditLineList mMergeEditLineList; 0102 0103 public: 0104 [[nodiscard]] inline const MergeEditLineList& list() const { return mMergeEditLineList; } 0105 [[nodiscard]] inline MergeEditLineList& list() { return mMergeEditLineList; } 0106 0107 [[nodiscard]] inline e_SrcSelector source() const { return srcSelect; } 0108 0109 [[nodiscard]] inline LineType getIndex() const { return d3lLineIdx; } 0110 [[nodiscard]] inline LineType sourceRangeLength() const { return srcRangeLength; } 0111 0112 [[nodiscard]] inline bool isConflict() const { return bConflict; } 0113 [[nodiscard]] inline bool isWhiteSpaceConflict() const { return bWhiteSpaceConflict; } 0114 [[nodiscard]] inline bool isDelta() const { return bDelta; } 0115 [[nodiscard]] inline bool hasModfiedText() 0116 { 0117 return std::any_of(list().cbegin(), list().cend(), [](const MergeEditLine& mel) { return mel.isModified(); }); 0118 } 0119 0120 [[nodiscard]] inline Diff3LineList::const_iterator id3l() const { return mId3l; } 0121 0122 [[nodiscard]] inline e_MergeDetails details() const { return mergeDetails; } 0123 0124 [[nodiscard]] inline LineType lineCount() const { return SafeInt<qint32>(list().size()); } 0125 0126 void split(MergeBlock& mb2, LineType d3lLineIdx2) // The caller must insert the mb2 after this mb in the m_mergeLineList 0127 { 0128 if(d3lLineIdx2 < d3lLineIdx || d3lLineIdx2 >= d3lLineIdx + srcRangeLength) 0129 { 0130 assert(false); 0131 return; //Error 0132 } 0133 mb2.mergeDetails = mergeDetails; 0134 mb2.bConflict = bConflict; 0135 mb2.bWhiteSpaceConflict = bWhiteSpaceConflict; 0136 mb2.bDelta = bDelta; 0137 mb2.srcSelect = srcSelect; 0138 0139 mb2.d3lLineIdx = d3lLineIdx2; 0140 mb2.srcRangeLength = srcRangeLength - (d3lLineIdx2 - d3lLineIdx); 0141 srcRangeLength = d3lLineIdx2 - d3lLineIdx; // current MergeBlock controls fewer lines 0142 mb2.mId3l = mId3l; 0143 for(LineType i = 0; i < srcRangeLength; ++i) 0144 ++mb2.mId3l; 0145 0146 mb2.mMergeEditLineList.clear(); 0147 // Search for best place to splice 0148 for(MergeEditLineList::iterator i = mMergeEditLineList.begin(); i != mMergeEditLineList.end(); ++i) 0149 { 0150 if(i->id3l() == mb2.mId3l) 0151 { 0152 mb2.mMergeEditLineList.splice(mb2.mMergeEditLineList.begin(), mMergeEditLineList, i, mMergeEditLineList.end()); 0153 return; 0154 } 0155 } 0156 mb2.mMergeEditLineList.push_back(MergeEditLine(mb2.mId3l)); 0157 } 0158 0159 void join(MergeBlock& mb2) // The caller must remove the ml2 from the m_mergeLineList after this call 0160 { 0161 srcRangeLength += mb2.srcRangeLength; 0162 mb2.mMergeEditLineList.clear(); 0163 mMergeEditLineList.clear(); 0164 mMergeEditLineList.push_back(MergeEditLine(mId3l)); // Create a simple conflict 0165 if(mb2.bConflict) bConflict = true; 0166 if(!mb2.bWhiteSpaceConflict) bWhiteSpaceConflict = false; 0167 if(mb2.bDelta) bDelta = true; 0168 } 0169 0170 bool isSameKind(const MergeBlock& mb2) const; 0171 0172 void mergeOneLine(const Diff3Line& diffRec, bool& bLineRemoved, bool bTwoInputs); 0173 void dectectWhiteSpaceConflict(const Diff3Line& d, const bool isThreeWay); 0174 0175 void removeEmptySource(); 0176 }; 0177 0178 class MergeBlockList: public std::list<MergeBlock> 0179 { 0180 public: 0181 using std::list<MergeBlock>::list; 0182 0183 void buildFromDiff3(const Diff3LineList& diff3List, bool isThreeway); 0184 void updateDefaults(const e_SrcSelector defaultSelector, const bool bConflictsOnly, const bool bWhiteSpaceOnly); 0185 0186 MergeBlockList::iterator splitAtDiff3LineIdx(qint32 d3lLineIdx); 0187 }; 0188 0189 #endif