File indexing completed on 2024-12-08 11:06:03

0001 // clang-format off
0002 /**
0003  * KDiff3 - Text Diff And Merge Tool
0004  *
0005  * SPDX-FileCopyrightText: 2021 David Hallas <david@davidhallas.dk>
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  *
0008  */
0009 // clang-format on
0010 
0011 #include "GitIgnoreList.h"
0012 
0013 #include "Logging.h"
0014 #include "fileaccess.h"
0015 
0016 #include <algorithm>
0017 #include <utility>
0018 
0019 #include <QFile>
0020 #include <QStringList>
0021 #include <QTextStream>
0022 
0023 namespace {
0024 
0025 bool isComment(const QString& line)
0026 {
0027     return line.startsWith(QChar('#'));
0028 }
0029 
0030 } // namespace
0031 
0032 GitIgnoreList::GitIgnoreList() = default;
0033 
0034 GitIgnoreList::~GitIgnoreList() = default;
0035 
0036 void GitIgnoreList::enterDir(const QString& dir, const DirectoryList& directoryList)
0037 {
0038     const auto directoryListIt = std::find_if(directoryList.begin(), directoryList.end(), [](const FileAccess& file) {
0039         return file.fileName() == ".gitignore";
0040     });
0041     if(directoryListIt != directoryList.end())
0042     {
0043         addEntries(dir, readFile(directoryListIt->absoluteFilePath()));
0044     }
0045 }
0046 
0047 bool GitIgnoreList::matches(const QString& dir, const QString& text, bool bCaseSensitive) const
0048 {
0049     for(auto& dirPattern: m_patterns)
0050     {
0051         if(!dir.startsWith(dirPattern.first))
0052         {
0053             continue;
0054         }
0055         for(QRegularExpression& pattern: dirPattern.second)
0056         {
0057             if(!bCaseSensitive)
0058             {
0059                 pattern.setPatternOptions(QRegularExpression::CaseInsensitiveOption | QRegularExpression::UseUnicodePropertiesOption);
0060             }
0061             else
0062             {
0063                 pattern.setPatternOptions(QRegularExpression::UseUnicodePropertiesOption);
0064             }
0065             const QRegularExpressionMatch match = pattern.match(text);
0066             if(match.hasMatch())
0067             {
0068                 qCDebug(kdiffGitIgnoreList) << "Matched entry" << text;
0069                 return true;
0070             }
0071         }
0072     }
0073     return false;
0074 }
0075 
0076 QString GitIgnoreList::readFile(const QString& fileName) const
0077 {
0078     QFile file(fileName);
0079     if(!file.open(QIODevice::ReadOnly))
0080     {
0081         return QString();
0082     }
0083     QTextStream stream(&file);
0084     return stream.readAll();
0085 }
0086 
0087 void GitIgnoreList::addEntries(const QString& dir, const QString& lines)
0088 {
0089     static const QRegularExpression newLineReg = QRegularExpression("[\r\n]");
0090     const QStringList lineList = lines.split(newLineReg, Qt::SkipEmptyParts);
0091     for(const QString& line: lineList)
0092     {
0093         if(isComment(line))
0094         {
0095             continue;
0096         }
0097         QRegularExpression expression(QRegularExpression::wildcardToRegularExpression(line));
0098         if(!expression.isValid())
0099         {
0100             qCDebug(kdiffGitIgnoreList) << "Expression" << line << "is not valid - skipping ...";
0101             continue;
0102         }
0103         qCDebug(kdiffGitIgnoreList) << "Adding entry [" << dir << "]" << line;
0104         m_patterns[dir].push_back(expression);
0105     }
0106 }