summaryrefslogtreecommitdiff
path: root/src/plugins/git/commitdata.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/git/commitdata.cpp')
-rw-r--r--src/plugins/git/commitdata.cpp128
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;