File indexing completed on 2024-05-12 05:52:07

0001 /*
0002     SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de>
0003     SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
0004     SPDX-FileCopyrightText: 2020 Jonathan Verner <jonathan.verner@matfyz.cz>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 #pragma once
0009 
0010 #include <QList>
0011 #include <memory>
0012 
0013 class QUrl;
0014 class QString;
0015 
0016 /**
0017  * A class representing a unified diff, possibly with
0018  * conflict markers.
0019  *
0020  * A diff is assumed to be a collection of hunks, where each hunk has the
0021  * following structure:
0022  *
0023  *   METADATA
0024  *   --- a/SOURCE_PATH
0025  *   +++ b/TARGET_PATH
0026  *   HUNK1 HEADER
0027  *   HUNK1 CONTENT
0028  *   [METADATA]
0029  *   HUNK2 HEADER
0030  *   HUNK2 CONTENT
0031  *   ...
0032  *
0033  * METADATA are lines which start with anything except for a '+', '-' and ' '.
0034  * The path specifications may optionally precede a hunk and are assumed to
0035  * apply to all following hunks until a new path specification
0036  * is found. These indicate the files for which the diff is generated.
0037  *
0038  * Hunk Header
0039  * ------------
0040  *
0041  * Each hunk header has the following form
0042  *
0043  *   @@ -SRC_OFFSET[, SRC_CHANGES_COUNT] +TGT_OFFSET[, TGT_CHANGES_COUNT] @@ Heading
0044  *
0045  * where the SRC_OFFSET is a 1-based line index pointing to the source file where
0046  * the hunk applies and TGT_OFFSET is a 1-based line index pointing to the target
0047  * file where the hunk applies. The optional SRC_CHANGES_COUNTS (assumed to be 1
0048  * if not present) specifies the number of context lines plus the number of
0049  * deleted lines. Similarly, the optional TGT_CHANGES_COUNT specifies the
0050  * number of context lines plus the number of added lines. The Heading, used as a
0051  * visual aid for users, is supposed to show the line where the nearest enclosing
0052  * function scope of the hunk starts.
0053  *
0054  * Hunk Content
0055  * ------------
0056  *
0057  * The hunk content is a collection of lines which starting with '+' (additions),
0058  * '-' (deletions) and ' ' (context lines; empty lines are also take to be context
0059  * lines). Additionally, a hunk may contain conflict markers which are of the form
0060  *
0061  *   >>>>>>> our ref
0062  *   our content
0063  *   ...
0064  *   =======
0065  *   their content
0066  *   ...
0067  *   <<<<<<< their ref
0068  *
0069  * and indicate unresolved conflicts.
0070  *
0071  */
0072 class VcsDiff
0073 {
0074 public:
0075     /* Used to represent a patch or its inverse */
0076     enum DiffDirection {
0077         Normal = 0 /**< the unchanged patch */
0078         ,
0079         Forward = 0 /**< the unchanged patch */
0080         ,
0081         Reverse = 1 /**< the inverse of the patch (i.e. a new patch which, when applied, undoes the old patch) */
0082     };
0083 
0084     VcsDiff();
0085     ~VcsDiff();
0086     VcsDiff(VcsDiff &&rhs);
0087 
0088     /**
0089      * @returns the source of the diff.
0090      */
0091     QString diff() const;
0092 
0093     /** @returns the base directory of the diff. */
0094     QUrl baseDiff() const;
0095 
0096     /**
0097      * Depth - number of directories to left-strip from paths in the patch - see "patch -p"
0098      * Defaults to 0
0099      */
0100     uint depth() const;
0101 
0102     /** Sets the base directory of the diff to the @p url */
0103     void setBaseDiff(const QUrl &url);
0104 
0105     /** Sets the depth of the diff to @p depth */
0106     void setDepth(const uint depth);
0107 
0108     /** Sets the diff source and parses it.
0109      *
0110      * @param diff the diff in unified diff format
0111      */
0112     void setDiff(const QString &diff);
0113 
0114     /** @returns whether or not there are changes in the diff */
0115     bool isEmpty() const;
0116 
0117     /**
0118      * Creates a standalone diff containing the differences in a given range.
0119      *
0120      * @returns a diff containing only the changes from the current diff
0121      *  which are in the range startLine-endLine (in the diff text)
0122      *
0123      * @param startLine 0-based line number (in the diff) of the first line in the range
0124      * @param endLine 0-based line number (in the diff) of the last line in the range
0125      * @param dir if set to Reverse, the role of src and tgt are reversed, i.e. a diff is
0126      *            generated which can be applied to the target to get the source.
0127      */
0128     VcsDiff subDiff(const uint startLine, const uint endLine, DiffDirection dir = Normal) const;
0129 
0130     /**
0131      * Creates a new standalone diff from a single hunk identified by a containing line.
0132      *
0133      * @returns a diff containing only the changes from hunk containing
0134      * the line the line
0135      *
0136      * @param line 0-based line number (in the diff) of the line in the hunk
0137      * @param dir if set to Reverse, the role of src and tgt are reversed, i.e. a diff is
0138      *            generated which can be applied to the target to get the source.
0139      */
0140     VcsDiff subDiffHunk(const uint line, DiffDirection dir = Normal) const;
0141 
0142     /**
0143      * Maps a line position in the diff to a corresponding line position in the source file.
0144      *
0145      * @param line a 0-based line position in the diff
0146      * @returns the 0-based line position in the source file or -1 if no such position exists.
0147      */
0148     int diffLineToSourceLine(const uint line) const;
0149 
0150     /**
0151      * Maps a line position in the diff to a corresponding line position in the source file.
0152      *
0153      * @param line a 0-based line position in the diff
0154      * @returns the 0-based line position in the source file or -1 if no such position exists.
0155      */
0156     int diffLineToTargetLine(const uint line) const;
0157 
0158 private:
0159     std::unique_ptr<class VcsDiffPrivate> d;
0160 };
0161 
0162 // Helper, parses "123, 12" into ints
0163 std::pair<uint, uint> parseRange(const QString &range);