diff options
Diffstat (limited to 'src/plugins/git/commitdata.cpp')
-rw-r--r-- | src/plugins/git/commitdata.cpp | 128 |
1 files changed, 128 insertions, 0 deletions
diff --git a/src/plugins/git/commitdata.cpp b/src/plugins/git/commitdata.cpp index 8b96fe23c9..ada478e374 100644 --- a/src/plugins/git/commitdata.cpp +++ b/src/plugins/git/commitdata.cpp @@ -32,8 +32,12 @@ ***************************************************************************/ #include "commitdata.h" +#include <utils/qtcassert.h> #include <QtCore/QDebug> +#include <QtCore/QRegExp> + +const char *const kBranchIndicatorC = "# On branch"; namespace Git { namespace Internal { @@ -85,6 +89,130 @@ void CommitData::clear() untrackedFiles.clear(); } +// Split a state/file spec from git status output +// '#<tab>modified:<blanks>git .pro' +// into state and file ('modified', 'git .pro'). +CommitData::StateFilePair splitStateFileSpecification(const QString &line) +{ + QPair<QString, QString> rc; + const int statePos = 2; + const int colonIndex = line.indexOf(QLatin1Char(':'), statePos); + if (colonIndex == -1) + return rc; + rc.first = line.mid(statePos, colonIndex - statePos); + int filePos = colonIndex + 1; + const QChar blank = QLatin1Char(' '); + while (line.at(filePos) == blank) + filePos++; + if (filePos < line.size()) + rc.second = line.mid(filePos, line.size() - filePos); + return rc; +} + +// Convenience to add a state/file spec to a list +static inline bool addStateFileSpecification(const QString &line, QList<CommitData::StateFilePair> *list) +{ + const CommitData::StateFilePair sf = splitStateFileSpecification(line); + if (sf.first.isEmpty() || sf.second.isEmpty()) + return false; + list->push_back(sf); + return true; +} + +/* Parse a git status file list: + * \code + # Changes to be committed: + #<tab>modified:<blanks>git.pro + # Changed but not updated: + #<tab>modified:<blanks>git.pro + # Untracked files: + #<tab>git.pro + \endcode +*/ + +bool CommitData::parseFilesFromStatus(const QString &output) +{ + enum State { None, CommitFiles, NotUpdatedFiles, UntrackedFiles }; + + const QStringList lines = output.split(QLatin1Char('\n')); + const QString branchIndicator = QLatin1String(kBranchIndicatorC); + const QString commitIndicator = QLatin1String("# Changes to be committed:"); + const QString notUpdatedIndicator = QLatin1String("# Changed but not updated:"); + const QString untrackedIndicator = QLatin1String("# Untracked files:"); + + State s = None; + // Match added/changed-not-updated files: "#<tab>modified: foo.cpp" + QRegExp filesPattern(QLatin1String("#\\t[^:]+:\\s+.+")); + QTC_ASSERT(filesPattern.isValid(), return false); + + const QStringList::const_iterator cend = lines.constEnd(); + for (QStringList::const_iterator it = lines.constBegin(); it != cend; ++it) { + const QString line = *it; + if (line.startsWith(branchIndicator)) { + panelInfo.branch = line.mid(branchIndicator.size() + 1); + } else { + if (line.startsWith(commitIndicator)) { + s = CommitFiles; + } else { + if (line.startsWith(notUpdatedIndicator)) { + s = NotUpdatedFiles; + } else { + if (line.startsWith(untrackedIndicator)) { + // Now match untracked: "#<tab>foo.cpp" + s = UntrackedFiles; + filesPattern = QRegExp(QLatin1String("#\\t.+")); + QTC_ASSERT(filesPattern.isValid(), return false); + } else { + if (filesPattern.exactMatch(line)) { + switch (s) { + case CommitFiles: + addStateFileSpecification(line, &stagedFiles); + break; + case NotUpdatedFiles: + addStateFileSpecification(line, &unstagedFiles); + break; + case UntrackedFiles: + untrackedFiles.push_back(line.mid(2).trimmed()); + break; + case None: + break; + } + } + } + } + } + } + } + return !stagedFiles.empty() || !unstagedFiles.empty() || !untrackedFiles.empty(); +} + +// Convert a spec pair list to a list of file names, optionally +// filter for a state +static QStringList specToFileNames(const QList<CommitData::StateFilePair> &files, + const QString &stateFilter) +{ + typedef QList<CommitData::StateFilePair>::const_iterator ConstIterator; + if (files.empty()) + return QStringList(); + const bool emptyFilter = stateFilter.isEmpty(); + QStringList rc; + const ConstIterator cend = files.constEnd(); + for (ConstIterator it = files.constBegin(); it != cend; ++it) + if (emptyFilter || stateFilter == it->first) + rc.push_back(it->second); + return rc; +} + +QStringList CommitData::stagedFileNames(const QString &stateFilter) const +{ + return specToFileNames(stagedFiles, stateFilter); +} + +QStringList CommitData::unstagedFileNames(const QString &stateFilter) const +{ + return specToFileNames(unstagedFiles, stateFilter); +} + QDebug operator<<(QDebug d, const CommitData &data) { d << data.panelInfo << data.panelData; |