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