File indexing completed on 2024-12-08 13:30:48
0001 // clang-format off 0002 /* 0003 * This file is part of KDiff3. 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 DIFF_H 0012 #define DIFF_H 0013 0014 #include "common.h" 0015 #include "LineRef.h" 0016 #include "Logging.h" 0017 #include "TypeUtils.h" 0018 0019 #include <list> 0020 #include <memory> 0021 #include <vector> 0022 0023 #include <QSharedPointer> 0024 #include <QString> 0025 #include <QStringList> 0026 #include <QVector> 0027 0028 class LineData; 0029 0030 class Options; 0031 0032 using LineDataVector=std::vector<LineData>; 0033 0034 //e_SrcSelector must be sequential integers with no gaps between Min and Max. 0035 enum class e_SrcSelector 0036 { 0037 Min = -1, 0038 Invalid = -1, 0039 None = 0, 0040 A = 1, 0041 B = 2, 0042 C = 3, 0043 Max = C 0044 }; 0045 0046 inline e_SrcSelector nextSelector(e_SrcSelector selector) 0047 { 0048 switch(selector) 0049 { 0050 case e_SrcSelector::None: 0051 return e_SrcSelector::A; 0052 case e_SrcSelector::A: 0053 return e_SrcSelector::B; 0054 case e_SrcSelector::B: 0055 return e_SrcSelector::C; 0056 default: 0057 return e_SrcSelector::Invalid; 0058 } 0059 } 0060 0061 enum class e_MergeDetails 0062 { 0063 eDefault, 0064 eNoChange, 0065 eBChanged, 0066 eCChanged, 0067 eBCChanged, // conflict 0068 eBCChangedAndEqual, // possible conflict 0069 eBDeleted, 0070 eCDeleted, 0071 eBCDeleted, // possible conflict 0072 0073 eBChanged_CDeleted, // conflict 0074 eCChanged_BDeleted, // conflict 0075 eBAdded, 0076 eCAdded, 0077 eBCAdded, // conflict 0078 eBCAddedAndEqual // possible conflict 0079 }; 0080 0081 enum ChangeFlag 0082 { 0083 NoChange = 0, 0084 AChanged = 0x1, 0085 BChanged = 0x2, 0086 Both = AChanged | BChanged 0087 }; 0088 0089 Q_DECLARE_FLAGS(ChangeFlags, ChangeFlag); 0090 Q_DECLARE_OPERATORS_FOR_FLAGS(ChangeFlags); 0091 0092 // Each range with matching elements is followed by a range with differences on either side. 0093 // Then again range of matching elements should follow. 0094 class Diff 0095 { 0096 private: 0097 SafeInt<LineType> nofEquals = 0; 0098 0099 SafeInt<quint64> mDiff1 = 0; 0100 SafeInt<quint64> mDiff2 = 0; 0101 0102 public: 0103 Diff() = default; //We use default initialization force compiler to generate a default constructor 0104 Diff(LineType eq, const quint64 inDiff1, const quint64 inDiff2) 0105 { 0106 assert(eq >= 0); 0107 nofEquals = eq; 0108 mDiff1 = inDiff1; 0109 mDiff2 = inDiff2; 0110 } 0111 0112 [[nodiscard]] bool isEmpty() const { return nofEquals == 0 && mDiff1 == 0 && mDiff2 == 0;} 0113 0114 [[nodiscard]] inline qint32 numberOfEquals() const { return nofEquals; }; 0115 0116 [[nodiscard]] inline quint64 diff1() const { return mDiff1; }; 0117 [[nodiscard]] inline quint64 diff2() const { return mDiff2; }; 0118 0119 inline void setNumberOfEquals(const qint32 inNumOfEquals) { nofEquals = inNumOfEquals; } 0120 0121 inline void adjustNumberOfEquals(const qint64 delta) { nofEquals += delta; } 0122 inline void adjustDiff1(const qint64 delta) { mDiff1 += delta; } 0123 inline void adjustDiff2(const qint64 delta) { mDiff2 += delta; } 0124 0125 bool operator==(const Diff& b) const 0126 { 0127 return nofEquals == b.nofEquals && mDiff1 == b.mDiff1 && mDiff2 == b.mDiff2; 0128 }; 0129 0130 bool operator!=(const Diff& b) const 0131 { 0132 return !(*this == b); 0133 }; 0134 0135 inline void refine() 0136 { 0137 if(nofEquals < 4 && (mDiff1 > 0 || mDiff2 > 0)) 0138 { 0139 mDiff1 += nofEquals; 0140 mDiff2 += nofEquals; 0141 nofEquals = 0; 0142 } 0143 } 0144 }; 0145 0146 class DiffList: public std::list<Diff> 0147 { 0148 public: 0149 using std::list<Diff>::list; 0150 void calcDiff(const QString& line1, const QString& line2, const qint32 maxSearchRange); 0151 void runDiff(const std::shared_ptr<LineDataVector>& p1, const size_t index1, LineRef size1, const std::shared_ptr<LineDataVector>& p2, const size_t index2, LineRef size2); 0152 #ifndef NDEBUG 0153 void verify(const LineRef size1, const LineRef size2); 0154 #endif 0155 void optimize(); 0156 }; 0157 0158 class LineData 0159 { 0160 private: 0161 QSharedPointer<QString> mBuffer; 0162 QtSizeType mFirstNonWhiteChar = 0; 0163 //This tracks the offset with-in our unicode buffer not the file offset 0164 QtSizeType mOffset = 0; 0165 QtSizeType mSize = 0; 0166 bool bContainsPureComment = false; 0167 bool bSkipable = false;//TODO: Move me 0168 0169 public: 0170 inline LineData(const QSharedPointer<QString>& buffer, const QtSizeType inOffset, QtSizeType inSize = 0, QtSizeType inFirstNonWhiteChar = 0, bool inIsSkipable = false, const bool inIsPureComment = false) 0171 { 0172 mBuffer = buffer; 0173 mOffset = inOffset; 0174 mSize = inSize; 0175 bContainsPureComment = inIsPureComment; 0176 bSkipable = inIsSkipable; 0177 mFirstNonWhiteChar = inFirstNonWhiteChar; 0178 } 0179 [[nodiscard]] inline QtSizeType size() const { return mSize; } 0180 [[nodiscard]] inline QtSizeType getFirstNonWhiteChar() const { return mFirstNonWhiteChar; } 0181 0182 /* 0183 QString::fromRawData allows us to create a light weight QString backed by the buffer memory. 0184 */ 0185 [[nodiscard]] inline const QString getLine() const { return QString::fromRawData(mBuffer->data() + mOffset, mSize); } 0186 [[nodiscard]] inline const QSharedPointer<QString>& getBuffer() const { return mBuffer; } 0187 0188 [[nodiscard]] inline QtSizeType getOffset() const { return mOffset; } 0189 [[nodiscard]] qint32 width(qint32 tabSize) const; // Calcs width considering tabs. 0190 0191 [[nodiscard]] inline bool whiteLine() const { return mFirstNonWhiteChar == 0; } 0192 0193 [[nodiscard]] inline bool isPureComment() const { return bContainsPureComment; } 0194 inline void setPureComment(const bool bPureComment) { bContainsPureComment = bPureComment; } 0195 0196 [[nodiscard]] inline bool isSkipable() const { return bSkipable; } 0197 inline void setSkipable(const bool inSkipable) { bSkipable = inSkipable; } 0198 0199 [[nodiscard]] static bool equal(const LineData& l1, const LineData& l2); 0200 }; 0201 0202 class ManualDiffHelpList; // A list of corresponding ranges 0203 0204 class Diff3Line; 0205 class Diff3LineList; 0206 0207 using Diff3LineVector = QVector<Diff3Line*>; 0208 0209 class DiffBufferInfo 0210 { 0211 private: 0212 std::shared_ptr<LineDataVector> mLineDataA; 0213 std::shared_ptr<LineDataVector> mLineDataB; 0214 std::shared_ptr<LineDataVector> mLineDataC; 0215 const Diff3LineList* m_pDiff3LineList = nullptr; 0216 0217 public: 0218 void init(Diff3LineList* d3ll, 0219 const std::shared_ptr<LineDataVector> &pldA, const std::shared_ptr<LineDataVector> &pldB, const std::shared_ptr<LineDataVector> &pldC); 0220 0221 [[nodiscard]] inline std::shared_ptr<LineDataVector> getLineData(e_SrcSelector srcIndex) const 0222 { 0223 switch(srcIndex) 0224 { 0225 case e_SrcSelector::A: 0226 return mLineDataA; 0227 case e_SrcSelector::B: 0228 return mLineDataB; 0229 case e_SrcSelector::C: 0230 return mLineDataC; 0231 default: 0232 return nullptr; 0233 } 0234 } 0235 }; 0236 0237 enum class IgnoreFlag 0238 { 0239 none = 0, 0240 ignoreWhiteSpace = 1 << 1, 0241 ignoreComments = 1 << 2, 0242 }; 0243 0244 Q_DECLARE_FLAGS(IgnoreFlags, IgnoreFlag); 0245 Q_DECLARE_OPERATORS_FOR_FLAGS(IgnoreFlags); 0246 0247 class Diff3Line 0248 { 0249 protected: 0250 friend class Diff3LineList; 0251 LineRef lineA; 0252 LineRef lineB; 0253 LineRef lineC; 0254 0255 bool bAEqC = false; // These are true if equal or only white-space changes exist. 0256 bool bBEqC = false; 0257 bool bAEqB = false; 0258 0259 bool bWhiteLineA = false; 0260 bool bWhiteLineB = false; 0261 bool bWhiteLineC = false; 0262 0263 std::shared_ptr<const DiffList> pFineAB; // These are NULL only if completely equal or if either source doesn't exist. 0264 std::shared_ptr<const DiffList> pFineBC; 0265 std::shared_ptr<const DiffList> pFineCA; 0266 0267 qint32 mLinesNeededForDisplay = 1; // Due to wordwrap 0268 qint32 mSumLinesNeededForDisplay = 0; // For fast conversion to m_diff3WrapLineVector 0269 public: 0270 static QSharedPointer<DiffBufferInfo> m_pDiffBufferInfo; // Needed by this class and only this but inited directly from KDiff3App::mainInit 0271 0272 [[nodiscard]] inline bool hasFineDiffAB() const { return pFineAB != nullptr; } 0273 [[nodiscard]] inline bool hasFineDiffBC() const { return pFineBC != nullptr; } 0274 [[nodiscard]] inline bool hasFineDiffCA() const { return pFineCA != nullptr; } 0275 0276 [[nodiscard]] inline LineType getLineIndex(e_SrcSelector src) const 0277 { 0278 switch(src) 0279 { 0280 case e_SrcSelector::A: 0281 return getLineA(); 0282 case e_SrcSelector::B: 0283 return getLineB(); 0284 case e_SrcSelector::C: 0285 return getLineC(); 0286 default: 0287 assert(false); 0288 return LineRef::invalid; 0289 } 0290 } 0291 0292 [[nodiscard]] LineRef getLineA() const { return lineA; } 0293 [[nodiscard]] LineRef getLineB() const { return lineB; } 0294 [[nodiscard]] LineRef getLineC() const { return lineC; } 0295 0296 inline void setLineA(const LineRef& line) { lineA = line; } 0297 inline void setLineB(const LineRef& line) { lineB = line; } 0298 inline void setLineC(const LineRef& line) { lineC = line; } 0299 0300 [[nodiscard]] inline bool isEqualAB() const { return bAEqB; } 0301 [[nodiscard]] inline bool isEqualAC() const { return bAEqC; } 0302 [[nodiscard]] inline bool isEqualBC() const { return bBEqC; } 0303 0304 [[nodiscard]] inline bool isWhiteLine(e_SrcSelector src) const 0305 { 0306 assert(src == e_SrcSelector::A || src == e_SrcSelector::B || src == e_SrcSelector::C); 0307 0308 switch(src) 0309 { 0310 case e_SrcSelector::A: 0311 return bWhiteLineA; 0312 case e_SrcSelector::B: 0313 return bWhiteLineB; 0314 case e_SrcSelector::C: 0315 return bWhiteLineC; 0316 default: 0317 //should never get here 0318 assert(false); 0319 return false; 0320 } 0321 } 0322 0323 bool operator==(const Diff3Line& d3l) const 0324 { 0325 return lineA == d3l.lineA && lineB == d3l.lineB && lineC == d3l.lineC && 0326 bAEqB == d3l.bAEqB && bAEqC == d3l.bAEqC && bBEqC == d3l.bBEqC && 0327 bWhiteLineA == d3l.bWhiteLineA && bWhiteLineB == d3l.bWhiteLineB && bWhiteLineC == d3l.bWhiteLineC; 0328 } 0329 0330 [[nodiscard]] const LineData& getLineData(e_SrcSelector src) const 0331 { 0332 assert(m_pDiffBufferInfo != nullptr); 0333 assert(src == e_SrcSelector::A || src == e_SrcSelector::B || src == e_SrcSelector::C); 0334 //Use at() here not [] to avoid using really weird syntax 0335 if(src == e_SrcSelector::A && lineA.isValid()) return m_pDiffBufferInfo->getLineData(src)->at(lineA); 0336 if(src == e_SrcSelector::B && lineB.isValid()) return m_pDiffBufferInfo->getLineData(src)->at(lineB); 0337 return m_pDiffBufferInfo->getLineData(src)->at(lineC); 0338 } 0339 0340 [[nodiscard]] const QString getString(const e_SrcSelector src) const 0341 { 0342 const LineData& pld = getLineData(src); 0343 0344 return pld.getLine(); 0345 } 0346 0347 [[nodiscard]] LineRef getLineInFile(e_SrcSelector src) const 0348 { 0349 if(src == e_SrcSelector::A) return lineA; 0350 if(src == e_SrcSelector::B) return lineB; 0351 if(src == e_SrcSelector::C) return lineC; 0352 return LineRef(); 0353 } 0354 0355 [[nodiscard]] inline qint32 sumLinesNeededForDisplay() const { return mSumLinesNeededForDisplay; } 0356 0357 [[nodiscard]] inline qint32 linesNeededForDisplay() const { return mLinesNeededForDisplay; } 0358 0359 void setLinesNeeded(const qint32 lines) { mLinesNeededForDisplay = lines; } 0360 [[nodiscard]] bool fineDiff(bool bTextsTotalEqual, const e_SrcSelector selector, const std::shared_ptr<LineDataVector>& v1, const std::shared_ptr<LineDataVector>& v2, const IgnoreFlags eIgnoreFlags); 0361 void getLineInfo(const e_SrcSelector winIdx, const bool isTriple, LineRef& lineIdx, 0362 std::shared_ptr<const DiffList>& pFineDiff1, std::shared_ptr<const DiffList>& pFineDiff2, // return values 0363 ChangeFlags& changed, ChangeFlags& changed2) const; 0364 0365 private: 0366 void setFineDiff(const e_SrcSelector selector, const std::shared_ptr<DiffList>& pDiffList) 0367 { 0368 assert(selector == e_SrcSelector::A || selector == e_SrcSelector::B || selector == e_SrcSelector::C); 0369 if(selector == e_SrcSelector::A) 0370 { 0371 pFineAB = pDiffList; 0372 } 0373 else if(selector == e_SrcSelector::B) 0374 { 0375 pFineBC = pDiffList; 0376 } 0377 else if(selector == e_SrcSelector::C) 0378 { 0379 pFineCA = pDiffList; 0380 } 0381 } 0382 }; 0383 0384 struct HistoryRange; 0385 0386 class Diff3LineList: public std::list<Diff3Line> 0387 { 0388 public: 0389 using std::list<Diff3Line>::list; 0390 0391 void findHistoryRange(const QRegularExpression& historyStart, bool bThreeFiles, HistoryRange& range) const; 0392 bool fineDiff(const e_SrcSelector selector, const std::shared_ptr<LineDataVector> &v1, const std::shared_ptr<LineDataVector> &v2, const IgnoreFlags eIgnoreFlags); 0393 void calcDiff3LineVector(Diff3LineVector& d3lv); 0394 void calcWhiteDiff3Lines(const std::shared_ptr<LineDataVector> &pldA, const std::shared_ptr<LineDataVector> &pldB, const std::shared_ptr<LineDataVector> &pldC, const bool bIgnoreComments); 0395 0396 void calcDiff3LineListUsingAB(const DiffList* pDiffListAB); 0397 void calcDiff3LineListUsingAC(const DiffList* pDiffListAC); 0398 void calcDiff3LineListUsingBC(const DiffList* pDiffListBC); 0399 0400 void correctManualDiffAlignment(ManualDiffHelpList* pManualDiffHelpList); 0401 0402 void calcDiff3LineListTrim(const std::shared_ptr<LineDataVector> &pldA, const std::shared_ptr<LineDataVector> &pldB, const std::shared_ptr<LineDataVector> &pldC, ManualDiffHelpList* pManualDiffHelpList); 0403 0404 LineType recalcWordWrap(bool resetDisplayCount) 0405 { 0406 LineType sumOfLines = 0; 0407 0408 for(Diff3Line& d3l: *this) 0409 { 0410 if(resetDisplayCount) 0411 d3l.mLinesNeededForDisplay = 1; 0412 0413 d3l.mSumLinesNeededForDisplay = sumOfLines; 0414 sumOfLines += d3l.linesNeededForDisplay(); 0415 } 0416 0417 return sumOfLines; 0418 } 0419 0420 void debugLineCheck(const LineType size, const e_SrcSelector srcSelector) const; 0421 0422 void dump(); 0423 0424 [[nodiscard]] LineType numberOfLines(bool bWordWrap) const 0425 { 0426 if(bWordWrap) 0427 { 0428 LineType lines; 0429 0430 lines = 0; 0431 Diff3LineList::const_iterator i; 0432 for(i = begin(); i != end(); ++i) 0433 { 0434 lines += i->linesNeededForDisplay(); 0435 } 0436 0437 return lines; 0438 } 0439 else 0440 { 0441 return SafeInt<LineType>(size()); 0442 } 0443 } 0444 }; 0445 0446 struct HistoryRange 0447 { 0448 Diff3LineList::const_iterator start; 0449 Diff3LineList::const_iterator end; 0450 qint32 startIdx = -1; 0451 qint32 endIdx = -1; 0452 }; 0453 0454 struct Diff3WrapLine 0455 { 0456 Diff3Line* pD3L = nullptr; 0457 LineType diff3LineIndex = 0; 0458 qint32 wrapLineOffset = 0; 0459 qint32 wrapLineLength = 0; 0460 }; 0461 0462 typedef QVector<Diff3WrapLine> Diff3WrapLineVector; 0463 0464 class TotalDiffStatus 0465 { 0466 public: 0467 inline void reset() 0468 { 0469 bBinaryAEqC = false; 0470 bBinaryBEqC = false; 0471 bBinaryAEqB = false; 0472 bTextAEqC = false; 0473 bTextBEqC = false; 0474 bTextAEqB = false; 0475 nofUnsolvedConflicts = 0; 0476 nofSolvedConflicts = 0; 0477 nofWhitespaceConflicts = 0; 0478 } 0479 0480 [[nodiscard]] inline qint32 getUnsolvedConflicts() const { return nofUnsolvedConflicts; } 0481 inline void setUnsolvedConflicts(const qint32 unsolved) { nofUnsolvedConflicts = unsolved; } 0482 0483 [[nodiscard]] inline qint32 getSolvedConflicts() const { return nofSolvedConflicts; } 0484 inline void setSolvedConflicts(const qint32 solved) { nofSolvedConflicts = solved; } 0485 0486 [[nodiscard]] inline qint32 getWhitespaceConflicts() const { return nofWhitespaceConflicts; } 0487 inline void setWhitespaceConflicts(const qint32 wintespace) { nofWhitespaceConflicts = wintespace; } 0488 0489 [[nodiscard]] inline qint32 getNonWhitespaceConflicts() const { return getUnsolvedConflicts() + getSolvedConflicts() - getWhitespaceConflicts(); } 0490 0491 [[nodiscard]] bool isBinaryEqualAC() const { return bBinaryAEqC; } 0492 [[nodiscard]] bool isBinaryEqualBC() const { return bBinaryBEqC; } 0493 [[nodiscard]] bool isBinaryEqualAB() const { return bBinaryAEqB; } 0494 0495 void setBinaryEqualAC(const bool equal) { bBinaryAEqC = equal; } 0496 void setBinaryEqualBC(const bool equal) { bBinaryBEqC = equal; } 0497 void setBinaryEqualAB(const bool equal) { bBinaryAEqB = equal; } 0498 0499 [[nodiscard]] bool isTextEqualAC() const { return bTextAEqC; } 0500 [[nodiscard]] bool isTextEqualBC() const { return bTextBEqC; } 0501 [[nodiscard]] bool isTextEqualAB() const { return bTextAEqB; } 0502 0503 void setTextEqualAC(const bool equal) { bTextAEqC = equal; } 0504 void setTextEqualBC(const bool equal) { bTextBEqC = equal; } 0505 void setTextEqualAB(const bool equal) { bTextAEqB = equal; } 0506 0507 private: 0508 bool bBinaryAEqC = false; 0509 bool bBinaryBEqC = false; 0510 bool bBinaryAEqB = false; 0511 0512 bool bTextAEqC = false; 0513 bool bTextBEqC = false; 0514 bool bTextAEqB = false; 0515 qint32 nofUnsolvedConflicts = 0; 0516 qint32 nofSolvedConflicts = 0; 0517 qint32 nofWhitespaceConflicts = -1; 0518 }; 0519 0520 // Three corresponding ranges. (Minimum size of a valid range is one line.) 0521 class ManualDiffHelpEntry 0522 { 0523 private: 0524 LineRef lineA1; 0525 LineRef lineA2; 0526 LineRef lineB1; 0527 LineRef lineB2; 0528 LineRef lineC1; 0529 LineRef lineC2; 0530 0531 public: 0532 ManualDiffHelpEntry() = default; 0533 ManualDiffHelpEntry(e_SrcSelector winIdx, LineRef firstLine, LineRef lastLine) 0534 { 0535 if(winIdx == e_SrcSelector::A) 0536 { 0537 lineA1 = firstLine; 0538 lineA2 = lastLine; 0539 } 0540 else if(winIdx == e_SrcSelector::B) 0541 { 0542 lineB1 = firstLine; 0543 lineB2 = lastLine; 0544 } 0545 else 0546 { 0547 lineC1 = firstLine; 0548 lineC2 = lastLine; 0549 } 0550 } 0551 0552 LineRef& firstLine(e_SrcSelector winIdx) 0553 { 0554 return winIdx == e_SrcSelector::A ? lineA1 : (winIdx == e_SrcSelector::B ? lineB1 : lineC1); 0555 } 0556 0557 LineRef& lastLine(e_SrcSelector winIdx) 0558 { 0559 return winIdx == e_SrcSelector::A ? lineA2 : (winIdx == e_SrcSelector::B ? lineB2 : lineC2); 0560 } 0561 0562 bool isLineInRange(LineRef line, e_SrcSelector winIdx) 0563 { 0564 return line.isValid() && line >= firstLine(winIdx) && line <= lastLine(winIdx); 0565 } 0566 0567 bool operator==(const ManualDiffHelpEntry& r) const 0568 { 0569 return lineA1 == r.lineA1 && lineB1 == r.lineB1 && lineC1 == r.lineC1 && 0570 lineA2 == r.lineA2 && lineB2 == r.lineB2 && lineC2 == r.lineC2; 0571 } 0572 0573 qint32 calcManualDiffFirstDiff3LineIdx(const Diff3LineVector& d3lv); 0574 0575 void getRangeForUI(const e_SrcSelector winIdx, LineRef* rangeLine1, LineRef* rangeLine2) const 0576 { 0577 if(winIdx == e_SrcSelector::A) 0578 { 0579 *rangeLine1 = lineA1; 0580 *rangeLine2 = lineA2; 0581 } 0582 if(winIdx == e_SrcSelector::B) 0583 { 0584 *rangeLine1 = lineB1; 0585 *rangeLine2 = lineB2; 0586 } 0587 if(winIdx == e_SrcSelector::C) 0588 { 0589 *rangeLine1 = lineC1; 0590 *rangeLine2 = lineC2; 0591 } 0592 } 0593 0594 [[nodiscard]] inline const LineRef& getLine1(const e_SrcSelector winIdx) const { return winIdx == e_SrcSelector::A ? lineA1 : winIdx == e_SrcSelector::B ? lineB1 : lineC1;} 0595 [[nodiscard]] inline const LineRef& getLine2(const e_SrcSelector winIdx) const { return winIdx == e_SrcSelector::A ? lineA2 : winIdx == e_SrcSelector::B ? lineB2 : lineC2;} 0596 [[nodiscard]] bool isValidMove(LineRef line1, LineRef line2, e_SrcSelector winIdx1, e_SrcSelector winIdx2) const; 0597 }; 0598 0599 // A list of corresponding ranges 0600 class ManualDiffHelpList: public std::list<ManualDiffHelpEntry> 0601 { 0602 public: 0603 using std::list<ManualDiffHelpEntry>::list; 0604 0605 [[nodiscard]] bool isValidMove(LineRef line1, LineRef line2, e_SrcSelector winIdx1, e_SrcSelector winIdx2) const; 0606 void insertEntry(e_SrcSelector winIdx, LineRef firstLine, LineRef lastLine); 0607 0608 void runDiff(const std::shared_ptr<LineDataVector>& p1, LineRef size1, const std::shared_ptr<LineDataVector>& p2, LineRef size2, DiffList& diffList, 0609 e_SrcSelector winIdx1, e_SrcSelector winIdx2); 0610 }; 0611 0612 /** Returns the number of equivalent spaces at position outPos. 0613 */ 0614 inline qint32 tabber(qint32 outPos, qint32 tabSize) 0615 { 0616 return tabSize - (outPos % tabSize); 0617 } 0618 0619 /** Returns a line number where the linerange [line, line+nofLines] can 0620 be displayed best. If it fits into the currently visible range then 0621 the returned value is the current firstLine. 0622 */ 0623 LineRef getBestFirstLine(LineRef line, LineType nofLines, LineRef firstLine, LineType visibleLines); 0624 0625 enum e_CoordType 0626 { 0627 eFileCoords, 0628 eD3LLineCoords, 0629 eWrapCoords 0630 }; 0631 0632 QString calcHistorySortKey(const QString& keyOrder, QRegularExpressionMatch& matchedRegExpr, const QStringList& parenthesesGroupList); 0633 bool findParenthesesGroups(const QString& s, QStringList& sl); 0634 #endif