File indexing completed on 2024-04-28 04:37:46

0001 /*
0002     SPDX-FileCopyrightText: 2007 Andreas Pakulat <apaku@gmx.de>
0003     SPDX-FileCopyrightText: 2007 Matthew Woehlke <mw_triad@users.sourceforge.net>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #ifndef KDEVPLATFORM_VCSDIFF_H
0009 #define KDEVPLATFORM_VCSDIFF_H
0010 
0011 #include <QSharedDataPointer>
0012 #include <QtGlobal>
0013 #include <QMetaType>
0014 #include <QVector>
0015 
0016 
0017 #include "vcsexport.h"
0018 
0019 class QUrl;
0020 class QString;
0021 
0022 namespace KDevelop
0023 {
0024 
0025 /**
0026  * A class representing a unified diff, possibly with
0027  * conflict markers.
0028  *
0029  * A diff is assumed to be a collection of hunks, where each hunk has the
0030  * following structure:
0031  *
0032  *   METADATA
0033  *   --- a/SOURCE_PATH
0034  *   +++ b/TARGET_PATH
0035  *   HUNK1 HEADER
0036  *   HUNK1 CONTENT
0037  *   [METADATA]
0038  *   HUNK2 HEADER
0039  *   HUNK2 CONTENT
0040  *   ...
0041  *
0042  * METADATA are lines which start with anything except for a '+', '-' and ' '.
0043  * The path specifications may optionally precede a hunk and are assumed to
0044  * apply to all following hunks until a new path specification
0045  * is found. These indicate the files for which the diff is generated.
0046  *
0047  * Hunk Header
0048  * ------------
0049  *
0050  * Each hunk header has the following form
0051  *
0052  *   @@ -SRC_OFFSET[, SRC_CHANGES_COUNT] +TGT_OFFSET[, TGT_CHANGES_COUNT] @@ Heading
0053  *
0054  * where the SRC_OFFSET is a 1-based line index pointing to the source file where
0055  * the hunk applies and TGT_OFFSET is a 1-based line index pointing to the target
0056  * file where the hunk applies. The optional SRC_CHANGES_COUNTS (assumed to be 1
0057  * if not present) specifies the number of context lines plus the number of
0058  * deleted lines. Similarly, the optional TGT_CHANGES_COUNT specifies the
0059  * number of context lines plus the number of added lines. The Heading, used as a
0060  * visual aid for users, is supposed to show the line where the nearest enclosing
0061  * function scope of the hunk starts.
0062  *
0063  * Hunk Content
0064  * ------------
0065  *
0066  * The hunk content is a collection of lines which starting with '+' (additions),
0067  * '-' (deletions) and ' ' (context lines; empty lines are also take to be context
0068  * lines). Additionally, a hunk may contain conflict markers which are of the form
0069  *
0070  *   >>>>>>> our ref
0071  *   our content
0072  *   ...
0073  *   =======
0074  *   their content
0075  *   ...
0076  *   <<<<<<< their ref
0077  *
0078  * and indicate unresolved conflicts.
0079  *
0080  */
0081 class KDEVPLATFORMVCS_EXPORT VcsDiff
0082 {
0083 public:
0084     /* Used to represent a patch or its inverse */
0085     enum DiffDirection {
0086           Normal = 0        /**< the unchanged patch */
0087         , Foward = 0        /**< the unchanged patch */
0088         , Reverse = 1       /**< the inverse of the patch (i.e. a new patch which, when applied, undoes the old patch) */
0089     };
0090 
0091     VcsDiff();
0092     virtual ~VcsDiff();
0093     VcsDiff( const VcsDiff& );
0094 
0095     /**
0096      * @returns the source of the diff.
0097      */
0098     QString diff() const;
0099     
0100     /** @returns the base directory of the diff. */
0101     QUrl baseDiff() const;
0102 
0103     /**
0104      * Depth - number of directories to left-strip from paths in the patch - see "patch -p"
0105      * Defaults to 0
0106      */
0107     uint depth() const;
0108 
0109     /** Sets the base directory of the diff to the @p url */
0110     void setBaseDiff(const QUrl& url);
0111 
0112     /** Sets the depth of the diff to @p depth */
0113     void setDepth(const uint depth);
0114 
0115     /** Sets the diff source and parses it.
0116      *
0117      * @param diff the diff in unified diff format
0118      */
0119     void setDiff( const QString& diff);
0120 
0121     VcsDiff& operator=( const VcsDiff& rhs);
0122     
0123     /** @returns whether or not there are changes in the diff */
0124     bool isEmpty() const;
0125 
0126     /**
0127      * Creates a standalone diff containing the differences in a given range.
0128      *
0129      * @returns a diff containing only the changes from the current diff
0130      *  which are in the range startLine-endLine (in the diff text)
0131      *
0132      * @param startLine 0-based line number (in the diff) of the first line in the range
0133      * @param endLine 0-based line number (in the diff) of the last line in the range
0134      * @param dir if set to Reverse, the role of src and tgt are reversed, i.e. a diff is
0135      *            generated which can be applied to the target to get the source.
0136      */
0137     VcsDiff subDiff(const uint startLine, const uint endLine, DiffDirection dir = Normal) const;
0138 
0139     /**
0140      * Creates a new standalone diff from a single hunk identified by a containing line.
0141      *
0142      * @returns a diff containing only the changes from hunk containing
0143      * the line the line
0144      *
0145      * @param line 0-based line number (in the diff) of the line in the hunk
0146      * @param dir if set to Reverse, the role of src and tgt are reversed, i.e. a diff is
0147      *            generated which can be applied to the target to get the source.
0148      */
0149     VcsDiff subDiffHunk(const uint line, DiffDirection dir = Normal) const;
0150 
0151     /**
0152      * A struct representing a position in a source file.
0153      *
0154      * @note This should eventually be replaced with a @ref KDevelop::DocumentCursor,
0155      * which, however, currently cannot be used in this file.
0156      */
0157     struct SourceLocation {
0158         /* Path to the source file (may be relative) */
0159         QString path = {};
0160         /* 0-based line number in the source file */
0161         int line = -1;
0162     };
0163 
0164     /**
0165      * Maps a line position in the diff to a corresponding line position in the source file.
0166      *
0167      * @param line a 0-based line position in the diff
0168      * @returns a @ref SourceLocation whose path is the target file path (relative to diff root)
0169      *          and line the 0-based line position in the target file or {"", -1} if no such
0170      *          position exists.
0171      */
0172     SourceLocation diffLineToSource (const uint line) const;
0173 
0174     /**
0175      * Maps a line position in the diff to a corresponding line position in the target file.
0176      *
0177      * @param line a 0-based line position in the diff
0178      * @returns a @ref SourceLocation whose path is the source file path (relative to diff root)
0179      *          and line the 0-based line position in the source file or {"", -1} if no such
0180      *          position exists.
0181      */
0182     SourceLocation diffLineToTarget (const uint line) const;
0183 
0184     /**
0185      * Represents a pair of files which are compared
0186      */
0187     struct FilePair {
0188         QString source;
0189         QString target;
0190         bool operator==(const FilePair p) const {return (source == p.source && target == p.target); }
0191     };
0192 
0193     /**
0194      * @returns a list of filename pairs that the patch applies to
0195      *
0196      * @note: Each file-pair is only listed once for each consecutive run
0197      * of hunks which apply to it.
0198      */
0199     const QVector<FilePair> fileNames() const;
0200 
0201 private:
0202     QSharedDataPointer<class VcsDiffPrivate> d;
0203 };
0204 
0205 }
0206 
0207 Q_DECLARE_METATYPE( KDevelop::VcsDiff )
0208 Q_DECLARE_TYPEINFO( KDevelop::VcsDiff, Q_MOVABLE_TYPE );
0209 Q_DECLARE_TYPEINFO( KDevelop::VcsDiff::FilePair, Q_MOVABLE_TYPE );
0210 
0211 #endif
0212